/**
 * 沙发数据处理工具 - 核心逻辑
 * 功能：处理CSV数据，提取指定区域的压力值，并写入Excel模板
 */

// 全局变量，用于存储加载的模块
let manifest;

// 加载脚本函数
function loadScript(url) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = url;
    script.onload = resolve;
    script.onerror = reject;
    document.head.appendChild(script);
  });
}

// 在DOM加载完成后初始化模块
document.addEventListener('DOMContentLoaded', async () => {
  try {
    // 检查全局函数是否可用
    if (typeof window.sendMonitoringData !== 'function') {
      console.error('无法加载 sendMonitoringData 函数');
    }
    
    // 加载 manifest.json
    const response = await fetch('./manifest.json');
    manifest = await response.json();
    
    console.log('模块加载完成');
  } catch (error) {
    console.error('模块加载失败:', error);
  }
});

// 全局变量
let processedFilePaths = [];
let logPanel;
let logManager; // 日志管理器
let currentCSVFiles = []; // 存储当前上传的所有CSV文件
let currentFileIndex = 0; // 当前处理的文件索引
let activeProcessingTasks = 0; // 当前活跃的处理任务数
const MAX_PARALLEL_TASKS = 3; // 最大并行任务数
let processingQueue = []; // 处理队列
let isProcessingComplete = false; // 标记所有处理是否完成

// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
  logPanel = document.getElementById('logPanel');
  
  // 初始化日志管理器
  logManager = new LogManager(logPanel, {
    bufferSize: 15,      // 缓冲区大小
    debounceTime: 200,   // 防抖时间（毫秒）
    maxBufferTime: 1000  // 最大缓冲时间（毫秒）
  });
  
  // 设置Python脚本日志监听器
  setupPythonLogListeners();
  
  // 初始化验证功能事件监听器
  initValidationEventListeners();
  
  // 尝试创建桌面上的'Ergonomic data'文件夹
  try {
    if (fileAPI && fileAPI.ensureDirectoryExists) {
      // 使用fileAPI获取桌面路径
      fileAPI.getDesktopPath()
        .then((desktopResult) => {
          if (desktopResult.success && desktopResult.filePath) {
            const ergonomicDataFolder = `${desktopResult.filePath}\\Ergonomic data`;
            return fileAPI.ensureDirectoryExists(ergonomicDataFolder)
              .then(() => {
                addLog(`已确保目标文件夹存在: ${ergonomicDataFolder}`, 'info');
                
                // 初始化数据提取输入文件夹路径
                const dataExtractionInputFolder = document.getElementById('dataExtractionInputFolder');
                if (dataExtractionInputFolder) {
                  // 优先使用localStorage中保存的路径
                  const savedPath = localStorage.getItem('dataExtractionInputFolder');
                  if (savedPath) {
                    dataExtractionInputFolder.value = savedPath;
                    addLog(`已从本地存储加载输入文件夹路径: ${savedPath}`, 'info');
                  } else {
                    // 如果没有保存的路径，则使用默认的Ergonomic data文件夹路径
                    dataExtractionInputFolder.value = ergonomicDataFolder;
                    addLog(`已设置默认输入文件夹路径: ${ergonomicDataFolder}`, 'info');
                  }
                }
              });
          } else {
            addLog(`获取桌面路径失败: ${desktopResult.error || '未知错误'}`, 'warning');
          }
        })
        .catch((error) => {
          addLog(`创建目标文件夹失败: ${error.message}`, 'warning');
        });
    }
  } catch (error) {
    // 忽略错误，不影响应用正常运行
    console.error('创建目标文件夹失败:', error);
  }
  
  addLog('系统初始化完成', 'info', true); // 立即显示初始化日志
  
  // 检查Python环境
  checkPythonEnvironmentOnStartup();
  
  const uploadArea = document.getElementById('uploadArea');
  const fileInput = document.getElementById('fileInput');
  const processBtn = document.getElementById('processBtn');
  
  // 点击上传区域触发文件选择
  uploadArea.addEventListener('click', () => {
    fileInput.click();
  });
  
  // 文件选择变更事件
  fileInput.addEventListener('change', (e) => {
    if (e.target.files.length > 0) {
      handleFileUpload(e.target.files);
    }
  });
  
  // 处理按钮点击事件
  processBtn.addEventListener('click', () => {
    startProcessing();
  });

  // 新增：为"提取数据"按钮添加事件监听器
  const extractDataBtn = document.getElementById('extractDataBtn');
  if (extractDataBtn) {
    extractDataBtn.addEventListener('click', () => {
      handleExtractData();
    });
  }
  
  // 为"填充模板"按钮添加事件监听器
  const fillTemplateBtn = document.getElementById('fillTemplateBtn');
  console.log('填充模板按钮元素:', fillTemplateBtn);
  if (fillTemplateBtn) {
    console.log('成功绑定填充模板按钮事件');
    fillTemplateBtn.addEventListener('click', () => {
      handleFillWordTemplate();
    });
  } else {
    console.error('未找到填充模板按钮元素');
  }
  
  // 为"After文件处理"按钮添加事件监听器
  const processAfterBtn = document.getElementById('processAfterBtn');
  if (processAfterBtn) {
    processAfterBtn.addEventListener('click', () => {
      handleProcessAfterFile();
    });
  }
  
  // 为"离散系数计算"按钮添加事件监听器
  const calculateCVBtn = document.getElementById('calculateCVBtn');
  if (calculateCVBtn) {
    calculateCVBtn.addEventListener('click', () => {
      handleCalculateCV();
    });
  }
  
  // 为离散系数CSV文件上传添加事件监听器
  const cvFileInput = document.getElementById('cvFileInput');
  if (cvFileInput) {
    cvFileInput.addEventListener('change', (e) => {
      if (e.target.files.length > 0) {
        handleCVFileUpload(e.target.files[0]);
      }
    });
  }
  
  // 为保存JSON按钮添加事件监听器
  const saveJsonBtn = document.getElementById('saveJsonBtn');
  if (saveJsonBtn) {
    saveJsonBtn.addEventListener('click', () => {
      handleSaveJsonFile();
    });
  }
  
  // 为离散系数重置按钮添加事件监听器
  // 重新上传CSV按钮事件监听器
  const cvReuploadBtn = document.getElementById('cvReuploadBtn');
  if (cvReuploadBtn) {
    cvReuploadBtn.addEventListener('click', () => {
      // 隐藏结果容器、调试数据容器、保存按钮容器和进度条
      const cvResultsContainer = document.getElementById('cvResultsContainer');
      const debugDataContainer = document.getElementById('debugDataContainer');
      const saveJsonContainer = document.getElementById('saveJsonContainer');
      const cvProgressContainer = document.getElementById('cvProgressContainer');
      if (cvResultsContainer) {
        cvResultsContainer.style.display = 'none';
      }
      if (debugDataContainer) {
        debugDataContainer.style.display = 'none';
      }
      if (saveJsonContainer) {
        saveJsonContainer.style.display = 'none';
      }
      if (cvProgressContainer) {
        cvProgressContainer.style.display = 'none';
      }
      
      // 重置文件输入
      const cvFileInput = document.getElementById('cvFileInput');
      if (cvFileInput) {
        cvFileInput.value = '';
      }
      
      // 重置起始帧数和计算帧数输入
      const startFrameInput = document.getElementById('startFrameInput');
      const frameIndexInput = document.getElementById('frameIndexInput');
      if (startFrameInput) {
        startFrameInput.value = '1';
      }
      if (frameIndexInput) {
        frameIndexInput.value = '1';
      }
      
      // 重置全局变量
      cvFile = null;
      
      // 恢复拖放区域的原始显示（不重新设置innerHTML以保持事件监听器）
      const cvDropZone = document.getElementById('cv-drop-zone');
      if (cvDropZone) {
        // 移除可能存在的highlight类
        cvDropZone.classList.remove('highlight');
        // 恢复原始内容而不破坏事件监听器
        cvDropZone.innerHTML = `
          <div class="upload-icon">
            <i class="bi bi-file-earmark-spreadsheet fs-1"></i>
          </div>
          <h5>点击或拖拽CSV文件到此处</h5>
          <p class="text-muted">支持.csv格式文件</p>
          <input type="file" id="cvFileInput" accept=".csv" style="display: none;">
        `;
        
        // 重新绑定文件输入事件监听器
        const newCvFileInput = document.getElementById('cvFileInput');
        if (newCvFileInput) {
          newCvFileInput.addEventListener('change', (e) => {
            if (e.target.files.length > 0) {
              handleCVFileUpload(e.target.files[0]);
            }
          });
        }
      }
      
      // 隐藏已选择文件的显示
      const cvSelectedFile = document.getElementById('cv-selected-file');
      if (cvSelectedFile) {
        cvSelectedFile.style.display = 'none';
      }
      
      // 重置计算按钮状态
      const calculateBtn = document.getElementById('calculateCVBtn');
      if (calculateBtn) {
        calculateBtn.innerHTML = '<i class="bi bi-calculator me-2"></i> 开始计算';
        calculateBtn.disabled = false;
      }
      
      // 隐藏重置按钮组，但保持计算按钮容器隐藏（等待文件上传后显示）
      const resetButtonsContainer = document.getElementById('cvResetButtonsContainer');
      if (resetButtonsContainer) {
        resetButtonsContainer.style.display = 'none';
      }
      
      // 隐藏Frame Index容器
      const frameIndexContainer = document.getElementById('cvFrameIndexContainer');
      if (frameIndexContainer) {
        frameIndexContainer.style.display = 'none';
      }
      
      // 隐藏计算按钮容器
      const calculateContainer = document.getElementById('cvCalculateContainer');
      if (calculateContainer) {
        calculateContainer.style.display = 'none';
      }
      
      addLog('已重置到文件上传状态，请重新上传CSV文件', 'info');
    });
  }
  
  // 重新输入Index按钮事件监听器
  const cvReindexBtn = document.getElementById('cvReindexBtn');
  if (cvReindexBtn) {
    cvReindexBtn.addEventListener('click', () => {
      // 隐藏结果容器和调试数据容器
      const cvResultsContainer = document.getElementById('cvResultsContainer');
      const debugDataContainer = document.getElementById('debugDataContainer');
      if (cvResultsContainer) {
        cvResultsContainer.style.display = 'none';
      }
      if (debugDataContainer) {
        debugDataContainer.style.display = 'none';
      }
      
      // 只重置起始帧数和计算帧数输入，保留已上传的文件
      const startFrameInput = document.getElementById('startFrameInput');
      const frameIndexInput = document.getElementById('frameIndexInput');
      if (startFrameInput) {
        startFrameInput.value = '1';
      }
      if (frameIndexInput) {
        frameIndexInput.value = '1';
        frameIndexInput.focus(); // 聚焦到输入框
      }
      
      // 重置计算按钮状态为"开始计算"
      const calculateBtn = document.getElementById('calculateCVBtn');
      if (calculateBtn) {
        calculateBtn.innerHTML = '<i class="bi bi-calculator me-2"></i> 开始计算';
        calculateBtn.disabled = false;
      }
      
      // 隐藏重置按钮组
      const resetButtonsContainer = document.getElementById('cvResetButtonsContainer');
      if (resetButtonsContainer) {
        resetButtonsContainer.style.display = 'none';
      }
      
      addLog('已重置Frame Index，请重新输入并计算', 'info');
    });
  }
  
  // 初始化离散系数拖放区域
  const cvDropZone = document.getElementById('cv-drop-zone');
  if (cvDropZone) {
    // 阻止默认行为以允许拖放
    ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
      cvDropZone.addEventListener(eventName, (e) => {
        e.preventDefault();
        e.stopPropagation();
      }, false);
    });

    // 高亮显示拖放区域
    ['dragenter', 'dragover'].forEach(eventName => {
      cvDropZone.addEventListener(eventName, () => {
        cvDropZone.classList.add('highlight');
      }, false);
    });

    ['dragleave', 'drop'].forEach(eventName => {
      cvDropZone.addEventListener(eventName, () => {
        cvDropZone.classList.remove('highlight');
      }, false);
    });

    // 处理拖放文件
    cvDropZone.addEventListener('drop', (e) => {
      const files = e.dataTransfer.files;
      if (files.length > 0) {
        handleCVFileUpload(files[0]);
      }
    }, false);
    
    // 添加点击事件来触发文件选择
    cvDropZone.addEventListener('click', () => {
      const cvFileInput = document.getElementById('cvFileInput');
      if (cvFileInput) {
        cvFileInput.click();
      }
    });
  }
  
  // 拖放文件上传
  uploadArea.addEventListener('dragover', (e) => {
    e.preventDefault();
    e.stopPropagation();
    uploadArea.classList.add('dragover');
  });
  
  uploadArea.addEventListener('dragleave', (e) => {
    e.preventDefault();
    e.stopPropagation();
    uploadArea.classList.remove('dragover');
  });
  
  uploadArea.addEventListener('drop', (e) => {
    e.preventDefault();
    e.stopPropagation();
    uploadArea.classList.remove('dragover');
    
    if (e.dataTransfer.files.length > 0) {
      handleFileUpload(e.dataTransfer.files);
    }
  });
});

// 注意：currentCSVData变量已被移除，现在使用processFileAsync直接处理文件

/**
 * 处理上传的文件
 * @param {FileList|File} files - 上传的CSV文件或文件列表
 */
function handleFileUpload(files) {
  // 重置当前文件列表和索引
  currentCSVFiles = [];
  currentFileIndex = 0;
  processedFilePaths = [];
  
  // 如果传入的是单个文件，转换为数组
  if (files instanceof File) {
    files = [files];
  }
  
  // 过滤出CSV文件
  for (let i = 0; i < files.length; i++) {
    if (files[i].name.toLowerCase().endsWith('.csv')) {
      currentCSVFiles.push(files[i]);
    }
  }
  
  if (currentCSVFiles.length === 0) {
    addLog('请上传有效的CSV文件', 'error', true); // 立即显示错误
    return;
  }
  
  addLog(`已上传 ${currentCSVFiles.length} 个CSV文件`, 'info', true); // 立即显示上传成功信息
  document.getElementById('uploadArea').style.display = 'none';
  
  // 检查文件名是否包含'after'
  const hasAfterFile = currentCSVFiles.some(file => file.name.toLowerCase().includes('after'));
  
  if (hasAfterFile) {
    // 显示After文件处理区域
    document.getElementById('afterFileMappingSection').style.display = 'block';
    document.getElementById('columnMappingSection').style.display = 'none';
    addLog('检测到文件名包含"after"，请选择Excel文件', 'info', true);
  } else {
    // 显示普通列映射设置区域
    document.getElementById('columnMappingSection').style.display = 'block';
    document.getElementById('afterFileMappingSection').style.display = 'none';
    // 设置默认列映射
    analyzeCSVFormat();
  }
}

// 注意：readCurrentCSVFile函数已被移除，现在使用processFileAsync进行并行文件处理

/**
 * 分析CSV文件格式并设置列映射
 * @param {string} csvData - CSV文件内容
 */
/**
 * 分析CSV格式并设置默认列映射
 * // 注意：此函数现在仅用于初始化界面，不再在文件处理流程中调用
 */
function analyzeCSVFormat() {
}

// 新增：处理数据提取
// 清除提取数据页面的提示信息
function clearExtractionAlerts() {
  // 查找extractDataBtn后面的所有alert元素并移除
  const extractDataBtn = document.getElementById('extractDataBtn');
  if (extractDataBtn) {
    let nextElement = extractDataBtn.nextElementSibling;
    while (nextElement && nextElement.classList.contains('alert')) {
      const alertToRemove = nextElement;
      nextElement = nextElement.nextElementSibling;
      alertToRemove.remove();
    }
  }
}

// 创建提示信息
function createExtractionAlert(type, message, autoClose = true) {
  // 清除之前的提示
  clearExtractionAlerts();
  
  // 创建提示元素
  const alertDiv = document.createElement('div');
  alertDiv.className = `alert alert-${type} alert-dismissible fade show mt-3`;
  
  // 设置图标
  let icon = 'info-circle';
  if (type === 'success') icon = 'check-circle';
  if (type === 'danger') icon = 'exclamation-triangle';
  if (type === 'warning') icon = 'exclamation-triangle';
  
  // 设置提示内容
  alertDiv.innerHTML = `
    <i class="bi bi-${icon}-fill me-2"></i>
    <strong>${type === 'success' ? '成功' : type === 'danger' ? '错误' : '提示'}：</strong> ${message}
    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
  `;
  
  // 添加到DOM
  const extractDataBtn = document.getElementById('extractDataBtn');
  extractDataBtn.insertAdjacentElement('afterend', alertDiv);
  
  // 自动关闭
  if (autoClose) {
    setTimeout(() => {
      alertDiv.classList.remove('show');
      setTimeout(() => alertDiv.remove(), 150);
    }, 5000);
  }
  
  return alertDiv;
}

async function handleExtractData() {
  // 获取输入文件夹路径
  const inputFolder = document.getElementById('dataExtractionInputFolder').value.trim();
  if (!inputFolder) {
    addLog('请输入包含Excel文件的文件夹路径。', 'error');
    return;
  }
  
  // 清除之前的提示信息
  clearExtractionAlerts();
  
  // 显示加载中提示
  createExtractionAlert('info', '正在获取数据，请稍后...', false);
  
  // 获取自定义帧数（可选）
  const customFrameNumber = document.getElementById('customFrameNumber').value.trim();
  
  // 显示加载提示和进度条
  document.getElementById('extractionProgressContainer').style.display = 'block';
  document.getElementById('extractionProgressBar').style.width = '10%';
  document.getElementById('extractionProgressText').textContent = '10%';
  
  // 修改按钮状态，防止重复点击
  const extractDataBtn = document.getElementById('extractDataBtn');
  const originalBtnText = extractDataBtn.innerHTML;
  extractDataBtn.innerHTML = '<i class="bi bi-hourglass-split me-1"></i> 请稍后...';
  extractDataBtn.disabled = true;
  
  addLog('开始从Excel文件提取数据...', 'info');
  addLog(`输入文件夹: ${inputFolder}`, 'info');
  if (customFrameNumber) {
    addLog(`七区自定义帧数: ${customFrameNumber}`, 'info');
  }
  
  // 显示提示信息
  addLog('正在获取数据，请稍后...', 'info');

  try {
    // 更新进度条到10%
    document.getElementById('extractionProgressBar').style.width = '10%';
    document.getElementById('extractionProgressText').textContent = '10%';
    addLog('正在检查Python依赖...', 'info');
    
    // 首先检查和安装Python依赖
    const dependencyResult = await pyAPI.runpyfile({
      scriptPath: './install_dependencies.py',
      pluginName: 'sofaData-process',
      args: []
    });
    
    if (!dependencyResult.success) {
      addLog(`依赖检查失败: ${dependencyResult.error}`, 'error');
      createExtractionAlert('danger', `依赖检查失败: ${dependencyResult.error}`, false);
      return;
    }
    
    // 解析依赖检查结果
    try {
      const depData = JSON.parse(dependencyResult.data);
      if (!depData.success) {
        addLog(`依赖安装失败: ${depData.error}`, 'error');
        createExtractionAlert('danger', `依赖安装失败: ${depData.error}`, false);
        return;
      }
      addLog('Python依赖检查完成', 'success');
    } catch (e) {
      addLog(`解析依赖检查结果失败: ${e.message}`, 'warning');
    }
    
    // 更新进度条到30%
    document.getElementById('extractionProgressBar').style.width = '30%';
    document.getElementById('extractionProgressText').textContent = '30%';
    addLog('正在调用Python脚本处理数据...', 'info');
    
    // 调用Python脚本，传递输入文件夹路径和自定义帧数
     const args = customFrameNumber ? [inputFolder, customFrameNumber] : [inputFolder];
     // 使用相对路径，并提供插件名称以便正确解析
     const result = await pyAPI.runpyfile({
       scriptPath: './extract_data.py',
       pluginName: 'sofaData-process',
       args: args
     });
     
    // 更新进度条到70%
    document.getElementById('extractionProgressBar').style.width = '70%';
    document.getElementById('extractionProgressText').textContent = '70%';

    if (result.success) {
      try {
        // 更新进度条到90%
        document.getElementById('extractionProgressBar').style.width = '90%';
        document.getElementById('extractionProgressText').textContent = '90%';
        addLog('正在解析返回数据...', 'info');
        
        const parsedData = JSON.parse(result.data);
        if (parsedData.success) {
          addLog('数据提取成功！', 'success');
          const jsonContent = document.getElementById('json-content');
          jsonContent.textContent = JSON.stringify(parsedData.data, null, 2);
          document.getElementById('json-output').style.display = 'block';
          
          // 显示成功提示
          createExtractionAlert('success', '数据已成功提取，可以查看下方JSON结果。');
        } else {
          addLog(`数据提取失败: ${parsedData.error}`, 'error');
          
          // 显示错误提示
          createExtractionAlert('danger', parsedData.error, false);
        }
      } catch (e) {
        addLog(`解析返回数据失败: ${e.message}`, 'error');
        
        // 显示错误提示
        createExtractionAlert('danger', `解析返回数据失败: ${e.message}`, false);
      }
    } else {
      addLog(`数据提取失败: ${result.error}`, 'error');
      
      // 显示错误提示
      createExtractionAlert('danger', result.error, false);
    }
  } catch (error) {
    addLog(`调用Python脚本时出错: ${error.message}`, 'error');
  } finally {
    // 恢复按钮状态
    const extractDataBtn = document.getElementById('extractDataBtn');
    extractDataBtn.innerHTML = '<i class="bi bi-search me-1"></i> 提取数据';
    extractDataBtn.disabled = false;
    
    // 更新进度条为100%
    document.getElementById('extractionProgressBar').style.width = '100%';
    document.getElementById('extractionProgressText').textContent = '100%';
    
    // 延迟后隐藏进度条（给用户时间看到完成状态）
    setTimeout(() => {
      document.getElementById('extractionProgressContainer').style.display = 'none';
    }, 1500);
  }
  
  // 设置默认列映射
  let maxPressureColumn = 2; // 默认第3列(C列)
  let avgPressureColumn = 6; // 默认第7列(G列)
  let contactAreaColumn = 8; // 默认第9列(I列)
  
  // 更新列映射界面
  document.getElementById('maxPressureColumn').value = maxPressureColumn;
  document.getElementById('avgPressureColumn').value = avgPressureColumn;
  document.getElementById('contactAreaColumn').value = contactAreaColumn;
  
  addLog(`已设置默认列映射：最大压力=${String.fromCharCode(65 + maxPressureColumn)}列, 平均值=${String.fromCharCode(65 + avgPressureColumn)}列, 接触面积=${String.fromCharCode(65 + contactAreaColumn)}列`, 'info');
  addLog(`请确认列映射设置，然后点击"处理数据"按钮继续`, 'info');
}

/**
 * 开始处理CSV数据
 */
function startProcessing() {
  if (currentCSVFiles.length === 0) {
    addLog('没有可处理的CSV文件', 'error', true); // 立即显示错误
    return;
  }
  
  // 显示进度条
  document.getElementById('columnMappingSection').style.display = 'none';
  document.getElementById('progressContainer').style.display = 'block';
  
  // 开始处理时立即显示日志
  addLog('开始处理数据...', 'info', true);
  
  // 获取手动列映射设置
  const useManualMapping = document.getElementById('useManualMapping').checked;
  
  // 获取输出文件夹路径（如果有指定）
  const outputFolderInput = document.getElementById('outputFolder');
  const outputFolder = outputFolderInput && outputFolderInput.value ? outputFolderInput.value.trim() : '';
  
  // 获取A列数据起始值设置
  const startValueInput = document.getElementById('startValue');
  const startValue = startValueInput && startValueInput.value ? parseInt(startValueInput.value) : null;
  
  // 设置A列数据配置
  let columnAConfig = null;
  if (startValue !== null) {
    columnAConfig = { start: startValue };
    addLog(`A列数据起始值设置: ${startValue}`, 'info');
  }
  
  // 输出文件夹设置将在processCSVFile中处理
  // 这里只记录用户的选择
  if (outputFolder) {
    addLog(`将保存文件到指定文件夹: ${outputFolder}`, 'info');
  } else {
    addLog(`未指定输出文件夹，将自动保存到桌面的'Ergonomic data'文件夹`, 'info');
  }
  
  // 重置处理状态
  currentFileIndex = 0;
  processedFilePaths = [];
  activeProcessingTasks = 0;
  processingQueue = [];
  isProcessingComplete = false;
  
  // 准备列映射设置
  let manualColumnIndices = null;
  if (useManualMapping) {
    addLog('使用手动列映射设置', 'info');
    
    // 获取用户设置的列索引
    manualColumnIndices = {
      maxPressure: parseInt(document.getElementById('maxPressureColumn').value) || 0,
      avgPressure: parseInt(document.getElementById('avgPressureColumn').value) || 0,
      contactArea: parseInt(document.getElementById('contactAreaColumn').value) || 0
    };
  } else {
    // 使用自动列映射
    addLog('使用自动列映射', 'info');
  }
  
  // 启动并行处理
  startParallelProcessing(manualColumnIndices, outputFolder, columnAConfig);
}

/**
 * 启动并行处理
 * @param {Object} manualColumnIndices - 手动列映射
 * @param {string} outputFolder - 输出文件夹路径
 * @param {Object} columnAConfig - A列数据配置设置
 */
function startParallelProcessing(manualColumnIndices, outputFolder, columnAConfig) {
  // 初始化处理队列
  for (let i = 0; i < currentCSVFiles.length; i++) {
    processingQueue.push(i);
  }
  
  addLog(`准备并行处理 ${currentCSVFiles.length} 个文件，最大并行任务数: ${MAX_PARALLEL_TASKS}`, 'info', true);
  
  // 使用requestIdleCallback或setTimeout来避免阻塞主线程
  if (requestIdleCallback) {
    requestIdleCallback(() => {
      // 启动初始的并行任务
      for (let i = 0; i < Math.min(MAX_PARALLEL_TASKS, currentCSVFiles.length); i++) {
        processNextFile(manualColumnIndices, outputFolder, columnAConfig);
      }
    });
  } else {
    // 兼容不支持requestIdleCallback的浏览器
    setTimeout(() => {
      // 启动初始的并行任务
      for (let i = 0; i < Math.min(MAX_PARALLEL_TASKS, currentCSVFiles.length); i++) {
        processNextFile(manualColumnIndices, outputFolder, columnAConfig);
      }
    }, 0);
  }
}

/**
 * 处理队列中的下一个文件
 * @param {Object} manualColumnIndices - 手动列映射
 * @param {string} outputFolder - 输出文件夹路径
 * @param {Object} columnAConfig - A列数据配置设置
 */
function processNextFile(manualColumnIndices, outputFolder, columnAConfig) {
  // 使用setTimeout避免长时间阻塞主线程
  setTimeout(() => {
    if (processingQueue.length === 0) {
      // 队列为空，检查是否所有任务都已完成
      checkProcessingCompletion();
      return;
    }
    
    // 从队列中取出下一个文件索引
    const fileIndex = processingQueue.shift();
    const file = currentCSVFiles[fileIndex];
    
    // 增加活跃任务计数
    activeProcessingTasks++;
    
    addLog(`开始处理文件 (${fileIndex + 1}/${currentCSVFiles.length}): "${file.name}"`, 'info');
    
    // 更新总体进度
    updateOverallProgress();
    
    // 异步读取和处理文件
    processFileAsync(file, fileIndex, manualColumnIndices, outputFolder, columnAConfig)
      .then(() => {
        // 减少活跃任务计数
        activeProcessingTasks--;
        
        // 使用requestAnimationFrame确保UI更新后再处理下一个文件
        requestAnimationFrame(() => {
          // 处理下一个文件
          processNextFile(manualColumnIndices, outputFolder, columnAConfig);
        });
      })
      .catch(error => {
        handleError(error);
        
        // 减少活跃任务计数
        activeProcessingTasks--;
        
        // 使用requestAnimationFrame确保UI更新后再处理下一个文件
        requestAnimationFrame(() => {
          // 继续处理下一个文件
          processNextFile(manualColumnIndices, outputFolder, columnAConfig);
        });
      });
  }, 0);
}

/**
 * 异步处理单个文件
 * @param {File} file - 要处理的文件
 * @param {number} fileIndex - 文件索引
 * @param {Object} manualColumnIndices - 手动列映射
 * @param {string} outputFolder - 输出文件夹路径
 * @param {Object} columnAConfig - A列数据配置设置
 * @returns {Promise} - 处理完成的Promise
 */
function processFileAsync(file, fileIndex, manualColumnIndices, outputFolder, columnAConfig) {
  return new Promise((resolve, reject) => {
    // 读取文件内容
    const reader = new FileReader();
    
    reader.onload = (e) => {
      try {
        const csvData = e.target.result;
        
        // 使用setTimeout将解析操作放入宏任务队列，避免长时间阻塞主线程
        setTimeout(async () => {
          try {
            // 解析CSV数据 - 现在parseCSV返回Promise
            const rows = await parseCSV(csvData, manualColumnIndices);
            addLog(`文件 "${file.name}": 成功解析CSV数据，共${rows.length}行`, 'success');
            
            // 使用requestAnimationFrame确保UI更新
            requestAnimationFrame(async () => {
              try {
                // 提取区域数据 - 现在extractRegionData返回Promise
                const regionData = await extractRegionData(rows);
                addLog(`文件 "${file.name}": 成功提取区域数据，找到${Object.keys(regionData).length}个区域`, 'success');
                
                // 使用setTimeout分解任务，避免长时间阻塞
                setTimeout(async () => {
                  try {
                    // 加载Excel模板
                    const templatePath = 'template.xlsx';
                    const workbook = await loadExcelTemplate(templatePath);
                    addLog(`文件 "${file.name}": 成功加载Excel模板`, 'success');
                    
                    // 写入数据到模板
                    await writeDataToTemplate(workbook, regionData, columnAConfig);
                    addLog(`文件 "${file.name}": 成功写入数据到模板`, 'success');
                    
                    // 生成输出文件名（基于原始文件名）
                    const outputFileName = file.name ? file.name.replace('.csv', '') : 'data';
                    
                    // 保存处理后的文件
                    const outputPath = await saveProcessedFile(workbook, outputFolder, outputFileName);
                    processedFilePaths.push(outputPath);
                    
                    addLog(`文件 "${file.name}": 处理完成`, 'success');
                    
                    // 获取用户设置
                    try {
                      const userSettings = await electronAPI.getUserSettings();
                      
                      // 构建监控数据
                      const monitoringData = {
                        user_name: userSettings.email?.split('@')[0] || 'unknown',
                        user_location: userSettings.site || 'unknown',
                        rpa_id: "140",
                        rpa_name: manifest.name,
                        rpa_version: manifest.version,
                        occurrence: new Date().toLocaleString('en-US', {
                          weekday: 'short',
                          day: '2-digit',
                          month: 'short',
                          year: 'numeric',
                          hour: '2-digit',
                          minute: '2-digit',
                          second: '2-digit',
                          hour12: false
                        }),
                        info: "人体工学数据处理",
                        extra: file.name
                      };
                      
                      // 发送监控数据
                      console.log('准备发送的监控数据：', monitoringData);
                      const monitoringResult = await sendMonitoringData([monitoringData]);
                      
                      if (monitoringResult.success) {
                        console.log(`监控数据发送成功 - 文件: ${file.name}`);
                      } else {
                        console.log(`监控数据发送失败 - 文件: ${file.name}, 错误信息: ${monitoringResult.message}`);
                      }
                    } catch (monitoringError) {
                      console.error(`发送监控数据时出错: ${monitoringError.message}`);
                    }
                    
                    // 更新进度
                    updateOverallProgress();
                    
                    resolve();
                  } catch (error) {
                    reject(error);
                  }
                }, 0);
              } catch (error) {
                reject(error);
              }
            });
          } catch (error) {
            reject(error);
          }
        }, 0);
      } catch (error) {
        reject(error);
      }
    };
    
    reader.onerror = () => {
      reject(new Error(`读取文件 "${file.name}" 失败`));
    };
    
    reader.readAsText(file);
  });
}

/**
 * 更新总体进度
 */
function updateOverallProgress() {
  const completedFiles = processedFilePaths.length;
  const totalFiles = currentCSVFiles.length;
  const overallProgress = Math.floor((completedFiles / totalFiles) * 100);
  
  updateProgress(overallProgress, `已处理 ${completedFiles}/${totalFiles} 个文件...`);
  
  // 如果所有文件都已处理完成，显示结果
  if (completedFiles === totalFiles && processingQueue.length === 0 && activeProcessingTasks === 0) {
    checkProcessingCompletion();
  }
}

/**
 * 检查处理是否全部完成
 */
function checkProcessingCompletion() {
  if (isProcessingComplete) return;
  
  if (processingQueue.length === 0 && activeProcessingTasks === 0) {
    isProcessingComplete = true;
    updateProgress(100, '所有文件处理完成');
    showBatchResult();
  }
}

/**
 * 处理CSV数据
 * @param {string} csvData - CSV文件内容
 * @param {Object} manualColumnIndices - 可选的手动列映射 {maxPressure, avgPressure, contactArea}
 * @param {string} outputFolder - 输出文件夹路径
 * @param {string} fileName - 原始文件名，用于生成输出文件名
 */
// 注意：processCSVData函数已被移除，现在使用processFileAsync进行并行文件处理

/**
 * 解析CSV数据
 * @param {string} csvData - CSV文件内容
 * @param {Object} manualColumnIndices - 可选的手动列映射 {maxPressure, avgPressure, contactArea}
 * @returns {Promise<Array>} - 解析后的数据行
 */
function parseCSV(csvData, manualColumnIndices = null) {
  return new Promise((resolve, reject) => {
    try {
      const lines = csvData.split('\n');
      const headerLine = lines[0];
      const headers = headerLine.split(',');
      const rows = [];
      
      // 检查前10行（或所有行，如果少于10行）以确定实际列数
      let actualMaxColumns = headers.length;
      const maxLinesToCheck = Math.min(10, lines.length);
      for (let i = 1; i < maxLinesToCheck; i++) {
        if (lines[i].trim()) {
          const rowColumns = lines[i].split(',').length;
          if (rowColumns > actualMaxColumns) {
            actualMaxColumns = rowColumns;
          }
        }
      }
      
      addLog(`CSV文件实际最大列数: ${actualMaxColumns}（标题行有${headers.length}列）`, 'info');
      
      // 查找关键列的索引
      const columnIndices = {
        maxPressure: -1, // C列 - 最大压力值
        avgPressure: -1, // G列 - 平均值
        contactArea: -1  // I列 - 接触面积
      };
      
      // 如果提供了手动列映射，则使用手动设置的列索引
      if (manualColumnIndices) {
        columnIndices.maxPressure = manualColumnIndices.maxPressure;
        columnIndices.avgPressure = manualColumnIndices.avgPressure;
        columnIndices.contactArea = manualColumnIndices.contactArea;
        
        addLog(`使用手动列映射: 最大压力=${columnIndices.maxPressure}, 平均值=${columnIndices.avgPressure}, 接触面积=${columnIndices.contactArea}`, 'info');
      } else {
        columnIndices.maxPressure = 2;
        columnIndices.avgPressure = 6;
        columnIndices.contactArea = 8;
      }
      
      addLog(`最终列映射: 最大压力=${columnIndices.maxPressure}(${String.fromCharCode(65 + columnIndices.maxPressure)}列), 平均值=${columnIndices.avgPressure}(${String.fromCharCode(65 + columnIndices.avgPressure)}列), 接触面积=${columnIndices.contactArea}(${String.fromCharCode(65 + columnIndices.contactArea)}列)`, 'info');
      
      // 记录最终确定的列索引和CSV文件的实际列数
      addLog(`最终确定的列索引: 最大压力=${columnIndices.maxPressure}, 平均值=${columnIndices.avgPressure}, 接触面积=${columnIndices.contactArea}`, 'info');
      
      // 使用分块处理方式处理CSV行，避免长时间阻塞主线程
      const CHUNK_SIZE = 500; // 每次处理500行
      const totalChunks = Math.ceil((lines.length - 1) / CHUNK_SIZE);
      let processedChunks = 0;
      
      // 处理一个数据块
      function processChunk(startIdx) {
        return new Promise(resolve => {
          // 使用setTimeout将处理放入下一个事件循环，避免长时间阻塞
          setTimeout(() => {
            const endIdx = Math.min(startIdx + CHUNK_SIZE, lines.length);
            const chunkRows = [];
            
            for (let i = startIdx; i < endIdx; i++) {
              const line = lines[i].trim();
              if (!line) continue;
              
              const values = line.split(',');
              
              const row = {
                columnIndices: columnIndices, // 将列索引保存在每一行中
                values: {}
              };
              
              // 保存所有列的值，确保不会超出数组范围
              for (let j = 0; j < actualMaxColumns; j++) {
                row.values[j] = (j < values.length && values[j]) ? values[j].trim() : '';
              }
              
              chunkRows.push(row);
            }
            
            // 将当前块的行添加到总行数组
            rows.push(...chunkRows);
            
            // 更新进度
            processedChunks++;
            const progress = Math.floor((processedChunks / totalChunks) * 100);
            if (processedChunks % 2 === 0 || processedChunks === totalChunks) {
              addLog(`CSV解析进度: ${progress}%`, 'info');
            }
            
            resolve();
          }, 0);
        });
      }
      
      // 处理所有数据块
      async function processAllChunks() {
        // 从第1行开始（跳过标题行）
        for (let i = 1; i < lines.length; i += CHUNK_SIZE) {
          await processChunk(i);
          
          // 使用requestAnimationFrame确保UI更新
          await new Promise(resolve => requestAnimationFrame(resolve));
        }
        
        resolve(rows);
      }
      
      // 开始处理
      processAllChunks().catch(reject);
    } catch (error) {
      reject(error);
    }
  });
}

/**
 * 提取指定区域的数据
 * @param {Array} rows - 解析后的数据行
 * @returns {Promise<Object>} - 提取的区域数据
 */
function extractRegionData(rows) {
  return new Promise((resolve, reject) => {
    try {
      const regionData = {};
      const targetRegions = ['Region 2', 'Region 3', 'Region 4', 'Region 5', 'Region 6', 'Region 7', 'Region 8', 'Region 9', 'Region 10'];
      
      // 记录找到的行数
      let totalRows = 0;
      let matchedRows = 0;
      
      // 使用分块处理方式处理行数据，避免长时间阻塞主线程
      const CHUNK_SIZE = 500; // 每次处理500行
      const totalChunks = Math.ceil(rows.length / CHUNK_SIZE);
      let processedChunks = 0;
      
      // 初始化区域数据对象
      targetRegions.forEach(region => {
        regionData[region] = [];
      });
      
      // 处理一个数据块
      function processChunk(startIdx) {
        return new Promise(resolve => {
          // 使用setTimeout将处理放入下一个事件循环，避免长时间阻塞
          setTimeout(() => {
            const endIdx = Math.min(startIdx + CHUNK_SIZE, rows.length);
            
            for (let i = startIdx; i < endIdx; i++) {
              const row = rows[i];
              totalRows++;
              
              // 检查第一列是否存在
              if (!row.values || !row.values.hasOwnProperty(0)) {
                addLog(`警告: 第${i + 1}行没有第一列数据`, 'warning');
                continue;
              }
              
              const firstColumn = row.values[0];
              if (!firstColumn) {
                addLog(`警告: 第${i + 1}行第一列为空`, 'warning');
                continue;
              }
              
              // 检查是否包含目标区域
              for (const region of targetRegions) {
                if (firstColumn.includes(region)) {
                  matchedRows++;
                  
                  // 只为前几个匹配项添加详细日志，避免日志过多
                  // if (matchedRows <= 5 || matchedRows % 10 === 0) {
                  //   addLog(`找到${region}数据行: 第${i + 1}行, 内容: "${firstColumn}"`, 'info');
                  // }
                  
                  // 获取列索引
                  const maxPressureIndex = row.columnIndices.maxPressure;
                  const avgPressureIndex = row.columnIndices.avgPressure;
                  const contactAreaIndex = row.columnIndices.contactArea;
                  
                  // 提取最大压力值、平均值和接触面积的数据
                  const maxPressureRaw = row.values[maxPressureIndex];
                  const avgPressureRaw = row.values[avgPressureIndex];
                  const contactAreaRaw = row.values[contactAreaIndex];
                  
                  // 只为前几个匹配项添加详细日志，避免日志过多
                  // if (matchedRows <= 3) {
                  //   addLog(`${region} 原始值: 最大压力[${maxPressureIndex}]="${maxPressureRaw}", 平均值[${avgPressureIndex}]="${avgPressureRaw}", 接触面积[${contactAreaIndex}]="${contactAreaRaw}"`, 'info');
                  // }
                  
                  const maxPressure = parseFloat(maxPressureRaw) || 0;
                  const avgPressure = parseFloat(avgPressureRaw) || 0;
                  const contactArea = parseFloat(contactAreaRaw) || 0;
                  
                  regionData[region].push({
                    maxPressure: maxPressure,
                    avgPressure: avgPressure,
                    contactArea: contactArea
                  });
                  
                  // 只为前几个匹配项添加详细日志，避免日志过多
                  // if (matchedRows <= 3 || matchedRows % 20 === 0) {
                  //   addLog(`找到${region}数据：最大压力=${maxPressure}, 平均值=${avgPressure}, 接触面积=${contactArea}`, 'info');
                  // }
                  break;
                }
              }
            }
            
            // 更新进度
            processedChunks++;
            const progress = Math.floor((processedChunks / totalChunks) * 100);
            if (processedChunks % 2 === 0 || processedChunks === totalChunks) {
              addLog(`区域数据提取进度: ${progress}%`, 'info');
            }
            
            resolve();
          }, 0);
        });
      }
      
      // 处理所有数据块
      async function processAllChunks() {
        for (let i = 0; i < rows.length; i += CHUNK_SIZE) {
          await processChunk(i);
          
          // 使用requestAnimationFrame确保UI更新
          await new Promise(resolve => requestAnimationFrame(resolve));
        }
        
        // 添加总结日志
        addLog(`CSV数据处理总结: 共处理${totalRows}行数据，匹配到${matchedRows}行区域数据`, 'info');
        
        // 检查是否有找到任何区域数据
        if (matchedRows === 0) {
          addLog(`警告: 未找到任何匹配的区域数据，请检查CSV文件格式是否正确`, 'warning');
        }
        
        // 检查每个区域是否有数据
        targetRegions.forEach(region => {
          if (!regionData[region] || regionData[region].length === 0) {
            addLog(`注意: 未找到${region}的数据`, 'info');
          } else {
            addLog(`成功提取${region}数据: ${regionData[region].length}行`, 'success');
          }
        });
        
        resolve(regionData);
      }
      
      // 开始处理
      processAllChunks().catch(reject);
    } catch (error) {
      reject(error);
    }
  });
}

/**
 * 加载Excel模板
 * @param {string} templatePath - 模板文件路径
 * @returns {Object} - 加载的工作簿
 */
async function loadExcelTemplate(templatePath) {
  return new Promise((resolve, reject) => {
    try {
      // 使用XLSX库加载模板
      const xhr = new XMLHttpRequest();
      xhr.open('GET', templatePath, true);
      xhr.responseType = 'arraybuffer';
      
      xhr.onload = function() {
        if (xhr.status === 200) {
          const arrayBuffer = xhr.response;
          
          // 使用setTimeout将XLSX.read操作放入宏任务队列，避免阻塞主线程
          setTimeout(() => {
            try {
              addLog('正在解析Excel模板...', 'info');
              const workbook = XLSX.read(arrayBuffer, { type: 'array' });
              
              // 使用requestAnimationFrame确保UI更新
              requestAnimationFrame(() => {
                resolve(workbook);
              });
            } catch (error) {
              reject(error);
            }
          }, 0);
        } else {
          reject(new Error(`加载模板失败，状态码：${xhr.status}`));
        }
      };
      
      xhr.onerror = function() {
        reject(new Error('加载模板时发生网络错误'));
      };
      
      xhr.send();
    } catch (error) {
      reject(error);
    }
  });
}

/**
 * 写入数据到模板
 * @param {Object} workbook - Excel工作簿
 * @param {Object} regionData - 区域数据
 * @param {Object} columnAConfig - A列数据配置设置
 * @returns {Promise} - 处理完成的Promise
 */
function writeDataToTemplate(workbook, regionData, columnAConfig) {
  return new Promise((resolve, reject) => {
    try {
      // 处理一个区域的数据
      function processRegionData(sheet, region, config, startIndex, endIndex) {
        return new Promise(resolve => {
          setTimeout(() => {
            const data = regionData[region];
            if (!data || data.length === 0 || startIndex >= data.length) {
              resolve();
              return;
            }
            
            const end = Math.min(endIndex, data.length);
            let rowIndex = startIndex + 2; // 从第2行开始写入
            
            for (let i = startIndex; i < end; i++) {
              const item = data[i];
              
              // 写入A列数据（如果设置了起始值）
              if (columnAConfig && columnAConfig.start !== null) {
                const currentIndex = startIndex + (i - startIndex);
                const columnAValue = columnAConfig.start + currentIndex;
                
                XLSX.utils.sheet_add_aoa(sheet, [[columnAValue]], { origin: `A${rowIndex}` });
              }
              
              // 写入最大压力值
              if (config.maxPressureCol) {
                XLSX.utils.sheet_add_aoa(sheet, [[item.maxPressure]], { origin: `${config.maxPressureCol}${rowIndex}` });
              }
              
              // 写入平均值
              if (config.avgPressureCol) {
                XLSX.utils.sheet_add_aoa(sheet, [[item.avgPressure]], { origin: `${config.avgPressureCol}${rowIndex}` });
                
                // 为'臀部左右'sheet的E列和I列设置百分数格式
                if (config.sheetName === '臀部左右' && (config.avgPressureCol === 'E' || config.avgPressureCol === 'I')) {
                  const cellRef = `${config.avgPressureCol}${rowIndex}`;
                  if (!sheet[cellRef]) {
                    sheet[cellRef] = {};
                  }
                  sheet[cellRef].z = '0.00%';
                  sheet[cellRef].t = 'n';
                  sheet[cellRef].v = item.avgPressure;
                }
              }
              
              // 为'臀部左右'添加计算列 - 直接计算数值
              if (config.sheetName === '臀部左右') {
                // 获取当前行的B、C、F、G列数据
                const bCellValue = sheet[`B${rowIndex}`] ? sheet[`B${rowIndex}`].v : 0;
                const cCellValue = sheet[`C${rowIndex}`] ? sheet[`C${rowIndex}`].v : 0;
                const fCellValue = sheet[`F${rowIndex}`] ? sheet[`F${rowIndex}`].v : 0;
                const gCellValue = sheet[`G${rowIndex}`] ? sheet[`G${rowIndex}`].v : 0;
                
                // D列计算：B列和C列的平均值
                if (region === 'Region 2' || region === 'Region 3') {
                  const dValue = (bCellValue + cCellValue) / 2;
                  const dCellRef = `D${rowIndex}`;
                  sheet[dCellRef] = {
                    v: dValue,
                    t: 'n'
                  };
                }
                
                // H列计算：F列和G列的平均值
                if (region === 'Region 2' || region === 'Region 3') {
                  const hValue = (fCellValue + gCellValue) / 2;
                  const hCellRef = `H${rowIndex}`;
                  sheet[hCellRef] = {
                    v: hValue,
                    t: 'n'
                  };
                }
                
                // E列计算：(C-B)/D - 每行都计算
                if (region === 'Region 2' || region === 'Region 3') {
                  const dValue = (bCellValue + cCellValue) / 2;
                  const eValue = dValue !== 0 ? (cCellValue - bCellValue) / dValue : 0;
                  const eCellRef = `E${rowIndex}`;
                  sheet[eCellRef] = {
                    v: eValue,
                    t: 'n',
                    z: '0.00%'
                  };
                }
                
                // I列计算：(G-F)/H - 每行都计算
                if (region === 'Region 2' || region === 'Region 3') {
                  const hValue = (fCellValue + gCellValue) / 2;
                  const iValue = hValue !== 0 ? (gCellValue - fCellValue) / hValue : 0;
                  const iCellRef = `I${rowIndex}`;
                  sheet[iCellRef] = {
                    v: iValue,
                    t: 'n',
                    z: '0.00%'
                  };
                }
              }
              
              // 写入接触面积
              if (config.contactAreaCol) {
                XLSX.utils.sheet_add_aoa(sheet, [[item.contactArea]], { origin: `${config.contactAreaCol}${rowIndex}` });
              }
              
              rowIndex++;
            }
            
            // 只记录部分日志，避免日志过多
            // if (startIndex === 0 || end === data.length) {
            //   addLog(`写入${region}数据到${config.sheetName}sheet，处理了${end - startIndex}行数据`, 'info');
            // }
            
            resolve();
          }, 0);
        });
      }
      
      // 处理所有区域的数据
      async function processAllRegions() {
        // 定义区域配置
        const regionConfigs = {
          'Region 2': { sheetName: '臀部左右', maxPressureCol: 'B', avgPressureCol: 'F', contactAreaCol: null },
          'Region 3': { sheetName: '臀部左右', maxPressureCol: 'C', avgPressureCol: 'G', contactAreaCol: null },
          'Region 4': { sheetName: '七区', maxPressureCol: 'B', avgPressureCol: 'C', contactAreaCol: 'P' },
          'Region 5': { sheetName: '七区', maxPressureCol: 'D', avgPressureCol: 'E', contactAreaCol: 'Q' },
          'Region 6': { sheetName: '七区', maxPressureCol: 'F', avgPressureCol: 'G', contactAreaCol: 'R' },
          'Region 7': { sheetName: '七区', maxPressureCol: 'H', avgPressureCol: 'I', contactAreaCol: 'S' },
          'Region 8': { sheetName: '七区', maxPressureCol: 'J', avgPressureCol: 'K', contactAreaCol: 'T' },
          'Region 9': { sheetName: '七区', maxPressureCol: 'L', avgPressureCol: 'M', contactAreaCol: 'U' },
          'Region 10': { sheetName: '七区', maxPressureCol: 'N', avgPressureCol: 'O', contactAreaCol: 'V' }
        };
        
        // 获取工作表
        const buttockSheet = workbook.Sheets['臀部左右'];
        const sevenRegionSheet = workbook.Sheets['七区'];
        
        if (!buttockSheet) {
          addLog('未找到"臀部左右"sheet', 'error');
        }
        
        if (!sevenRegionSheet) {
          addLog('未找到"七区"sheet', 'error');
        }
        
        // 分块处理每个区域的数据
        const CHUNK_SIZE = 100; // 每次处理100行
        
        for (const region in regionConfigs) {
          if (!regionData[region] || regionData[region].length === 0) {
            addLog(`注意: ${region}没有数据需要写入`, 'info');
            continue;
          }
          
          const config = regionConfigs[region];
          const sheet = config.sheetName === '臀部左右' ? buttockSheet : sevenRegionSheet;
          
          if (!sheet) continue;
          
          const totalRows = regionData[region].length;
          addLog(`开始写入${region}数据到${config.sheetName}sheet，共${totalRows}行`, 'info');
          
          // 分块处理
          for (let i = 0; i < totalRows; i += CHUNK_SIZE) {
            await processRegionData(sheet, region, config, i, i + CHUNK_SIZE);
            
            // 使用requestAnimationFrame确保UI更新
            if (i + CHUNK_SIZE < totalRows) {
              await new Promise(resolve => requestAnimationFrame(resolve));
            }
          }
          
          addLog(`完成${region}数据写入，共${totalRows}行`, 'success');
        }
        
        // 处理'臀部左右'sheet中max行数据：在所有数据写入完成后，在A列写入'max'，B列计算最大值
        try {
          addLog('处理"臀部左右"sheet中max行数据', 'info');
          const buttockSheetForMax = workbook.Sheets['臀部左右'];
          if (buttockSheetForMax) {
            const range = XLSX.utils.decode_range(buttockSheetForMax['!ref']);
            
            // 找到最后一行有数据的行号
            let lastDataRow = range.s.r; // 从标题行开始
            for (let R = range.s.r + 1; R <= range.e.r; ++R) {
              // 检查A列是否有数据（排除max行）
              const cellAddressA = XLSX.utils.encode_cell({ c: 0, r: R });
              const cellA = buttockSheetForMax[cellAddressA];
              if (cellA && cellA.v !== undefined && cellA.v !== null && cellA.v.toString().toLowerCase() !== 'max') {
                lastDataRow = R;
              }
            }
            
            // 计算B列的最大值，只计算数据行，不包括max行
            let maxBValue = null;
            for (let R = range.s.r + 1; R <= lastDataRow; ++R) { // 只计算到最后一行数据
              const cellAddressB = XLSX.utils.encode_cell({ c: 1, r: R }); // B列是索引1
              const cellB = buttockSheetForMax[cellAddressB];
              if (cellB && cellB.v !== undefined && cellB.v !== null) {
                const value = parseFloat(cellB.v);
                if (!isNaN(value)) {
                  if (maxBValue === null || value > maxBValue) {
                    maxBValue = value;
                  }
                }
              }
            }
            
            if (maxBValue !== null) {
              // 在最后一行数据后直接写入max行（不空行）
              const maxRowIndex = lastDataRow + 1;
              
              // 在A列写入'max'
              const maxCellA = XLSX.utils.encode_cell({ c: 0, r: maxRowIndex });
              buttockSheetForMax[maxCellA] = {
                v: 'max',
                t: 's'
              };
              
              // 在B列写入最大值
              const maxCellB = XLSX.utils.encode_cell({ c: 1, r: maxRowIndex });
              buttockSheetForMax[maxCellB] = {
                v: maxBValue,
                t: 'n'
              };
              
              // 更新工作表范围
              const newRange = XLSX.utils.encode_range({
                s: { c: range.s.c, r: range.s.r },
                e: { c: range.e.c, r: maxRowIndex }
              });
              buttockSheetForMax['!ref'] = newRange;
              
              addLog(`在"臀部左右"sheet第${maxRowIndex+1}行写入max行数据，B列最大值: ${maxBValue}`, 'success');
            } else {
              addLog('未找到B列的有效数值，跳过写入最大值', 'warning');
            }
          }
        } catch (maxError) {
          addLog(`处理"臀部左右"sheet max行时出错: ${maxError.message}`, 'warning');
        }
        
        // 处理'七区'sheet中max行数据：在所有数据写入完成后，空两行，然后在A列写入'max'，B列及后续列计算最大值
        try {
          addLog('处理"七区"sheet中max行数据', 'info');
          const sevenRegionSheetForMax = workbook.Sheets['七区'];
          if (sevenRegionSheetForMax) {
            const range = XLSX.utils.decode_range(sevenRegionSheetForMax['!ref']);
            
            // 找到最后一行有数据的行号
            let lastDataRow = range.s.r; // 从标题行开始
            for (let R = range.s.r + 1; R <= range.e.r; ++R) {
              // 检查A列是否有数据（排除max行）
              const cellAddressA = XLSX.utils.encode_cell({ c: 0, r: R });
              const cellA = sevenRegionSheetForMax[cellAddressA];
              if (cellA && cellA.v !== undefined && cellA.v !== null && cellA.v.toString().toLowerCase() !== 'max') {
                lastDataRow = R;
              }
            }
            
            // 计算B到O列的最大值 (列索引1到14)，只计算数据行，不包括max行
            const maxValues = {};
            for (let col = 1; col <= 14; col++) { // B列(1)到O列(14)
              maxValues[col] = null;
              for (let R = range.s.r + 1; R <= lastDataRow; ++R) { // 只计算到最后一行数据
                const cellAddress = XLSX.utils.encode_cell({ c: col, r: R });
                const cell = sevenRegionSheetForMax[cellAddress];
                if (cell && cell.v !== undefined && cell.v !== null) {
                  const value = parseFloat(cell.v);
                  if (!isNaN(value)) {
                    if (maxValues[col] === null || value > maxValues[col]) {
                      maxValues[col] = value;
                    }
                  }
                }
              }
            }
            
            // 在最后一行数据后空两行，然后写入max行
            const maxRowIndex = lastDataRow + 3; // 空两行后的第三行
            
            // 在A列写入'max'
            const maxCellA = XLSX.utils.encode_cell({ c: 0, r: maxRowIndex });
            sevenRegionSheetForMax[maxCellA] = {
              v: 'max',
              t: 's'
            };
            
            // 写入B到O列的最大值
            for (let col = 1; col <= 14; col++) { // B列(1)到O列(14)
              if (maxValues[col] !== null) {
                const cellAddress = XLSX.utils.encode_cell({ c: col, r: maxRowIndex });
                sevenRegionSheetForMax[cellAddress] = {
                  v: maxValues[col],
                  t: 'n'
                };
              }
            }
            
            // 更新工作表范围
            const newRange = XLSX.utils.encode_range({
              s: { c: range.s.c, r: range.s.r },
              e: { c: Math.max(range.e.c, 14), r: maxRowIndex }
            });
            sevenRegionSheetForMax['!ref'] = newRange;
            
            const colNames = ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'];
            addLog(`在"七区"sheet第${maxRowIndex+1}行写入max行数据，${colNames.join(',')}列最大值`, 'success');
            
            // 将获取的数据写入'一小时后'sheet中A列为'初始max'的行
            try {
              const oneHourLaterSheet = workbook.Sheets['一小时后'];
              if (oneHourLaterSheet) {
                const oneHourRange = XLSX.utils.decode_range(oneHourLaterSheet['!ref']);
                
                // 查找A列为'初始max'的行
                for (let oneHourR = oneHourRange.s.r + 1; oneHourR <= oneHourRange.e.r; ++oneHourR) {
                  const cellAddressA = XLSX.utils.encode_cell({ c: 0, r: oneHourR });
                  const cellA = oneHourLaterSheet[cellAddressA];
                  if (cellA && cellA.v && cellA.v.toString().toLowerCase() === '初始max') {
                    // 将七区的max行数据写入B到O列
                    for (let col = 1; col <= 14; col++) {
                      if (maxValues[col] !== null) {
                        const cellAddress = XLSX.utils.encode_cell({ c: col, r: oneHourR });
                        oneHourLaterSheet[cellAddress] = {
                          v: maxValues[col],
                          t: 'n'
                        };
                      }
                    }
                    addLog(`在"一小时后"sheet A列为"初始max"的行(第${oneHourR+1}行)写入七区max行数据`, 'success');
                    break;
                  }
                }
              } else {
                addLog('未找到"一小时后"sheet，跳过写入初始max行数据', 'warning');
              }
            } catch (oneHourError) {
              addLog(`处理"一小时后"sheet初始max行时出错: ${oneHourError.message}`, 'warning');
            }
          }
        } catch (maxError) {
          addLog(`处理"七区"sheet max行时出错: ${maxError.message}`, 'warning');
        }
        
        // 应用百分比格式
        try {
          addLog('为"臀部左右"sheet的E列和I列应用百分比格式', 'info');
          const sheetToFormat = workbook.Sheets['臀部左右'];
          if (sheetToFormat) {
            const range = XLSX.utils.decode_range(sheetToFormat['!ref']);
            for (let R = range.s.r + 1; R <= range.e.r; ++R) { // +1 to skip header
              // Format column E (index 4)
              const cellAddressE = XLSX.utils.encode_cell({ c: 4, r: R });
              const cellE = sheetToFormat[cellAddressE];
              if (cellE) {
                cellE.z = '0.00%';
              }

              // Format column I (index 8)
              const cellAddressI = XLSX.utils.encode_cell({ c: 8, r: R });
              const cellI = sheetToFormat[cellAddressI];
              if (cellI) {
                cellI.z = '0.00%';
              }
            }
            addLog('成功为“臀部左右”sheet的E列和I列应用百分比格式', 'success');
          } else {
            addLog('未找到“臀部左右”sheet，跳过格式化', 'warning');
          }
        } catch (formatError) {
          addLog(`应用单元格格式时出错: ${formatError.message}`, 'warning');
        }

        resolve();
      }
      
      // 开始处理
      processAllRegions().catch(reject);
    } catch (error) {
      reject(error);
    }
  });
}

/**
 * 保存处理后的文件
 * @param {Object} workbook - Excel工作簿
 * @param {string} outputFolder - 输出文件夹路径
 * @param {string} originalFileName - 原始CSV文件名
 * @returns {string} - 保存的文件路径
 */
async function saveProcessedFile(workbook, outputFolder = '', originalFileName = '') {
  return new Promise(async (resolve, reject) => {
    try {
      // 保留原文件名，只改变扩展名为.xlsx
      // 如果有原始文件名，直接使用它作为基础；否则使用默认名称
      const baseFileName = originalFileName ? originalFileName.replace('.csv', '') : 'data';
      const fileName = `${baseFileName}.xlsx`;
      
      // 设置默认保存到桌面的'Ergonomic data'文件夹
      let finalOutputFolder = outputFolder;
      
      // 如果没有指定输出文件夹，尝试使用桌面的'Ergonomic data'文件夹
      if (!finalOutputFolder && fileAPI && fileAPI.getDesktopPath) {
        try {
          // 等待异步获取桌面路径
          const desktopResult = await fileAPI.getDesktopPath();
          if (desktopResult.success && desktopResult.filePath) {
            const ergonomicDataFolder = `${desktopResult.filePath}\\Ergonomic data`;
            finalOutputFolder = ergonomicDataFolder;
            addLog(`将使用默认文件夹: ${ergonomicDataFolder}`, 'info');
          } else {
            addLog(`获取桌面路径失败: ${desktopResult.error || '未知错误'}，将使用浏览器下载`, 'warning');
            finalOutputFolder = '';
          }
        } catch (error) {
          addLog(`无法获取桌面路径: ${error.message}，将使用浏览器下载`, 'warning');
          finalOutputFolder = '';
        }
      }
      
      // 完整的输出路径
      const outputPath = finalOutputFolder ? `${finalOutputFolder}\\${fileName}` : fileName;
      
      // 使用setTimeout将耗时操作放入宏任务队列，避免阻塞主线程
      setTimeout(() => {
        try {
          
          addLog(`正在生成Excel文件...`, 'info');
          
          // 将工作簿转换为二进制数据 - 这是一个耗时操作
          const wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
          
          // 使用requestAnimationFrame确保UI更新
          requestAnimationFrame(() => {
            try {
              // 创建Blob对象
              const blob = new Blob([wbout], { type: 'application/octet-stream' });
              
              // 使用fileAPI保存文件
              if (fileAPI && fileAPI.saveFile && finalOutputFolder) {
                // 确保目标文件夹存在
                fileAPI.ensureDirectoryExists(finalOutputFolder)
                  .then(() => {
                    // 将Blob转换为ArrayBuffer后再保存
                    return new Promise((resolveBlob, rejectBlob) => {
                      const reader = new FileReader();
                      reader.onload = () => resolveBlob(reader.result);
                      reader.onerror = rejectBlob;
                      reader.readAsArrayBuffer(blob);
                    });
                  })
                  .then((arrayBuffer) => {
                    // 保存文件
                    return fileAPI.saveFile(outputPath, arrayBuffer);
                  })
                  .then(() => {
                    addLog(`文件已自动保存到：${outputPath}`, 'success');
                    resolve(outputPath);
                  })
                  .catch((error) => {
                    addLog(`保存文件失败：${error.message}，尝试使用浏览器下载`, 'warning');
                    // 如果自动保存失败，回退到浏览器下载
                    fallbackToBrowserDownload();
                  });
              } else {
                if (!fileAPI || !fileAPI.saveFile) {
                  addLog('未检测到fileAPI ，将使用浏览器下载功能', 'info');
                } else if (!finalOutputFolder) {
                  addLog('未指定有效的输出文件夹，将使用浏览器下载功能', 'info');
                }
                fallbackToBrowserDownload();
              }
              
              // 浏览器下载回退函数
              function fallbackToBrowserDownload() {
                // 创建下载链接
                const url = URL.createObjectURL(blob);
                
                // 自动下载文件
                const a = document.createElement('a');
                a.href = url;
                a.download = fileName;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                
                // 释放URL对象
                setTimeout(() => {
                  URL.revokeObjectURL(url);
                }, 1000);
                
                addLog(`文件已通过浏览器下载：${fileName}`, 'success');
                resolve(fileName);
              }
            } catch (error) {
              reject(error);
            }
          });
        } catch (error) {
          reject(error);
        }
      }, 0);
    } catch (error) {
      reject(error);
    }
  });
}

/**
 * 显示处理结果
 * @param {string} filePath - 处理后的文件路径
 */
function showResult(filePath) {
  document.getElementById('progressContainer').style.display = 'none';
  
  // 根据文件路径类型显示不同的消息
  if (filePath && filePath.includes('\\')) {
    // 如果是完整路径，显示保存位置
    document.getElementById('resultMessage').textContent = `数据处理成功，文件已自动保存到：${filePath}`;
  } else {
    // 如果只是文件名，说明是通过浏览器下载的
    document.getElementById('resultMessage').textContent = `数据处理成功，文件已下载：${filePath}`;
  }
  
  document.getElementById('resultSection').style.display = 'block';
  
  // 添加成功日志并立即显示
  if (filePath && filePath.includes('\\')) {
    addLog(`处理完成，文件已自动保存到：${filePath}`, 'success', true);
  } else {
    addLog(`处理完成，文件已下载：${filePath}`, 'success', true);
  }
  
  // 添加新的按钮事件
  document.getElementById('reuploadBtn').addEventListener('click', () => {
    resetToUpload();
  });
  
  document.getElementById('recalculateBtn').addEventListener('click', () => {
    resetToRecalculate();
  });
}

/**
 * 显示批量处理结果
 */
function showBatchResult() {
  document.getElementById('progressContainer').style.display = 'none';
  
  if (processedFilePaths.length === 0) {
    document.getElementById('resultMessage').textContent = '没有成功处理的文件';
    document.getElementById('resultMessage').className = 'alert alert-warning';
  } else {
    // 检查第一个处理后的文件路径，判断是自动保存还是浏览器下载
    const firstPath = processedFilePaths[0];
    const isAutoSaved = firstPath && firstPath.includes('\\');
    
    if (isAutoSaved) {
      // 如果是自动保存的，提取保存文件夹路径
      const folderPath = firstPath.substring(0, firstPath.lastIndexOf('\\'));
      document.getElementById('resultMessage').textContent = `批量处理完成，成功处理 ${processedFilePaths.length}/${currentCSVFiles.length} 个文件，已自动保存到：${folderPath}`;
    } else {
      document.getElementById('resultMessage').textContent = `批量处理完成，成功处理 ${processedFilePaths.length}/${currentCSVFiles.length} 个文件，已通过浏览器下载`;
    }
    document.getElementById('resultMessage').className = 'alert alert-success';
  }
  
  document.getElementById('resultSection').style.display = 'block';
  
  // 添加新的按钮事件
  document.getElementById('reuploadBtn').addEventListener('click', () => {
    resetToUpload();
  });
  
  document.getElementById('recalculateBtn').addEventListener('click', () => {
    resetToRecalculate();
  });
}

/**
 * 重置应用程序状态
 */
function resetApplication() {
  // 重置界面
  document.getElementById('progressContainer').style.display = 'none';
  document.getElementById('resultSection').style.display = 'none';
  document.getElementById('columnMappingSection').style.display = 'none';
  document.getElementById('uploadArea').style.display = 'block';
  
  // 重置日志
  if (logManager) {
    logManager.clear();
    logManager.addLog('系统就绪，等待上传CSV文件...', 'info', true);
  } else {
    document.getElementById('logPanel').innerHTML = `
      <h5 class="mb-3 d-flex align-items-center">
        <i class="bi bi-journal-text me-2"></i> 处理日志
      </h5>
      <div class="log-entry info">
        <i class="bi bi-info-circle me-1"></i>
        <span class="log-time">[初始化]</span>
        系统就绪，等待上传CSV文件...
      </div>
    `;
  }
  
  // 重置文件输入
  document.getElementById('fileInput').value = '';
  
  // 重置全局变量
  processedFilePaths = [];
  currentCSVFiles = [];
  currentFileIndex = 0;
  
  // 重置并行处理相关变量
  activeProcessingTasks = 0;
  processingQueue = [];
  isProcessingComplete = false;
  
  addLog('系统已重置，可以开始新的处理', 'info', true); // 立即显示重置消息
}

/**
 * 重新上传CSV - 完全重置到初始状态
 */
function resetToUpload() {
  // 调用完整的重置功能
  resetApplication();
  addLog('已重置到初始状态，请重新上传CSV文件', 'info', true);
}

/**
 * 重新计算 - 保留已上传的文件，重新显示列映射界面
 */
function resetToRecalculate() {
  // 隐藏结果和进度
  document.getElementById('progressContainer').style.display = 'none';
  document.getElementById('resultSection').style.display = 'none';
  
  // 显示列映射界面（如果有已上传的文件）
  if (currentCSVFiles && currentCSVFiles.length > 0) {
    document.getElementById('columnMappingSection').style.display = 'block';
    document.getElementById('uploadArea').style.display = 'none';
    
    // 重置处理状态但保留文件
    currentFileIndex = 0;
    processedFilePaths = [];
    activeProcessingTasks = 0;
    processingQueue = [];
    isProcessingComplete = false;
    
    // 清理日志但保留文件上传信息
    if (logManager) {
      logManager.clear();
      logManager.addLog(`已加载 ${currentCSVFiles.length} 个CSV文件，请重新配置列映射并开始处理`, 'info', true);
      // 重新显示文件信息
      currentCSVFiles.forEach((file, index) => {
        logManager.addLog(`文件 ${index + 1}: ${file.name}`, 'info');
      });
    }
    
    addLog('已重置计算设置，请重新配置列映射', 'info', true);
  } else {
    // 如果没有文件，则完全重置
    resetToUpload();
  }
}

/**
 * 更新进度条
 * @param {number} percent - 进度百分比
 * @param {string} message - 进度消息
 * @param {boolean} forceUpdate - 是否强制更新日志（默认为false，使用防抖机制）
 */
function updateProgress(percent, message, forceUpdate = false) {
  const progressBar = document.getElementById('progressBar');
  const progressText = document.getElementById('progressText');
  
  progressBar.style.width = `${percent}%`;
  progressText.textContent = `${percent}%`;
  
  // 进度为0%或100%时强制更新日志，其他情况使用防抖
  const immediate = forceUpdate || percent === 0 || percent === 100;
  addLog(message, 'info', immediate);
}

/**
 * 日志管理类 - 实现日志缓冲区、防抖和批量更新
 */
class LogManager {
  constructor(logPanelElement, options = {}) {
    this.logPanel = logPanelElement;
    this.logBuffer = []; // 日志缓冲区
    this.updateTimer = null; // 防抖定时器
    
    // 配置选项
    this.options = {
      bufferSize: options.bufferSize || 10, // 缓冲区大小，超过此值时自动刷新
      debounceTime: options.debounceTime || 300, // 防抖时间（毫秒）
      maxBufferTime: options.maxBufferTime || 2000 // 最大缓冲时间（毫秒）
    };
    
    this.lastUpdateTime = Date.now(); // 上次更新时间
    
    // 定期检查是否需要强制刷新
    setInterval(() => this.checkForceFlush(), this.options.maxBufferTime / 2);
  }
  
  /**
   * 添加日志到缓冲区
   * @param {string} message - 日志消息
   * @param {string} type - 日志类型（info, success, error）
   * @param {boolean} immediate - 是否立即显示（不经过缓冲区）
   */
  addLog(message, type = 'info', immediate = false) {
    const timestamp = new Date().toLocaleTimeString();
    const logItem = {
      timestamp,
      message,
      type
    };
    
    // 错误日志或immediate=true时立即显示
    if (type === 'error' || immediate) {
      this.renderLogItem(logItem);
      this.flushBuffer(); // 同时刷新缓冲区中的其他日志
      return;
    }
    
    // 添加到缓冲区
    this.logBuffer.push(logItem);
    
    // 如果缓冲区达到阈值，立即刷新
    if (this.logBuffer.length >= this.options.bufferSize) {
      this.flushBuffer();
      return;
    }
    
    // 设置防抖定时器
    this.debounceUpdate();
  }
  
  /**
   * 批量添加日志
   * @param {Array} logs - 日志数组，每项包含 {message, type}
   */
  addLogs(logs) {
    if (!Array.isArray(logs) || logs.length === 0) return;
    
    // 将所有日志添加到缓冲区
    logs.forEach(log => {
      this.logBuffer.push({
        timestamp: new Date().toLocaleTimeString(),
        message: log.message,
        type: log.type || 'info'
      });
    });
    
    // 立即刷新缓冲区
    this.flushBuffer();
  }
  
  /**
   * 防抖更新 - 延迟刷新缓冲区
   */
  debounceUpdate() {
    if (this.updateTimer) {
      clearTimeout(this.updateTimer);
    }
    
    this.updateTimer = setTimeout(() => {
      this.flushBuffer();
    }, this.options.debounceTime);
  }
  
  /**
   * 检查是否需要强制刷新（如果距离上次更新时间超过最大缓冲时间）
   */
  checkForceFlush() {
    const now = Date.now();
    if (this.logBuffer.length > 0 && now - this.lastUpdateTime > this.options.maxBufferTime) {
      this.flushBuffer();
    }
  }
  
  /**
   * 刷新缓冲区，将所有日志渲染到面板
   */
  flushBuffer() {
    if (this.logBuffer.length === 0) return;
    
    // 创建文档片段，提高性能
    const fragment = document.createDocumentFragment();
    
    // 限制每次渲染的日志数量，避免DOM操作过多导致卡顿
    const maxLogsPerRender = 20;
    const logsToRender = this.logBuffer.slice(0, maxLogsPerRender);
    
    // 将日志添加到文档片段
    logsToRender.forEach(logItem => {
      const logEntry = document.createElement('div');
      logEntry.className = `log-entry ${logItem.type}`;
      
      // 根据日志类型添加不同的图标
      let iconClass = '';
      switch(logItem.type) {
        case 'info':
          iconClass = 'bi bi-info-circle';
          break;
        case 'success':
          iconClass = 'bi bi-check-circle';
          break;
        case 'error':
          iconClass = 'bi bi-exclamation-triangle';
          break;
        case 'warning':
          iconClass = 'bi bi-exclamation-circle';
          break;
        default:
          iconClass = 'bi bi-dot';
      }
      
      logEntry.innerHTML = `
        <i class="${iconClass} me-1"></i>
        <span class="log-time">[${logItem.timestamp}]</span> 
        ${logItem.message}
      `;
      
      fragment.appendChild(logEntry);
    });
    
    // 一次性添加到DOM
    this.logPanel.appendChild(fragment);
    
    // 限制日志面板中的条目数量，避免DOM节点过多
    const maxLogEntries = 200;
    while (this.logPanel.childElementCount > maxLogEntries) {
      this.logPanel.removeChild(this.logPanel.firstChild);
    }
    
    // 滚动到底部
    requestAnimationFrame(() => {
      this.logPanel.scrollTop = this.logPanel.scrollHeight;
    });
    
    // 更新缓冲区
    this.logBuffer = this.logBuffer.slice(maxLogsPerRender);
    this.lastUpdateTime = Date.now();
    
    // 如果缓冲区中还有日志，安排下一次刷新
    if (this.logBuffer.length > 0) {
      setTimeout(() => this.flushBuffer(), 16); // 约60fps的刷新率
    }
  }
  
  /**
   * 渲染单个日志项
   * @param {Object} logItem - 日志项
   */
  renderLogItem(logItem) {
    const logEntry = document.createElement('div');
    logEntry.className = `log-entry ${logItem.type}`;
    
    // 根据日志类型添加不同的图标
    let iconClass = '';
    switch(logItem.type) {
      case 'info':
        iconClass = 'bi bi-info-circle';
        break;
      case 'success':
        iconClass = 'bi bi-check-circle';
        break;
      case 'error':
        iconClass = 'bi bi-exclamation-triangle';
        break;
      case 'warning':
        iconClass = 'bi bi-exclamation-circle';
        break;
      default:
        iconClass = 'bi bi-dot';
    }
    
    logEntry.innerHTML = `
      <i class="${iconClass} me-1"></i>
      <span class="log-time">[${logItem.timestamp}]</span> 
      ${logItem.message}
    `;
    
    this.logPanel.appendChild(logEntry);
    this.logPanel.scrollTop = this.logPanel.scrollHeight;
    this.lastUpdateTime = Date.now();
  }
  
  /**
   * 清空日志面板
   */
  clear() {
    this.logBuffer = [];
    if (this.updateTimer) {
      clearTimeout(this.updateTimer);
      this.updateTimer = null;
    }
    
    // 清空日志面板内容
    if (this.logPanel) {
      this.logPanel.innerHTML = '';
    }
  }
}

/**
 * 添加日志
 * @param {string} message - 日志消息
 * @param {string} type - 日志类型（info, success, error）
 * @param {boolean} immediate - 是否立即显示（不经过缓冲区）
 */
function addLog(message, type = 'info', immediate = false) {
  if (logManager) {
    logManager.addLog(message, type, immediate);
  } else if (logPanel) {
    // 兼容旧的日志系统
    const timestamp = new Date().toLocaleTimeString();
    const logEntry = document.createElement('div');
    logEntry.className = `log-entry ${type}`;
    logEntry.textContent = `[${timestamp}] ${message}`;
    
    logPanel.appendChild(logEntry);
    logPanel.scrollTop = logPanel.scrollHeight;
  }
}

/**
 * 批量添加日志
 * @param {Array} logs - 日志数组，每项包含 {message, type}
 */
function addLogs(logs) {
  if (!Array.isArray(logs) || logs.length === 0) return;
  
  if (logManager) {
    logManager.addLogs(logs);
  } else {
    // 兼容旧的日志系统，逐个添加日志
    logs.forEach(log => {
      addLog(log.message, log.type || 'info');
    });
  }
}

/**
 * 处理错误
 * @param {Error} error - 错误对象
 */
function handleError(error) {
  console.log(`错误：${error.message}`, 'error', true); // 错误日志立即显示
  updateProgress(0, '处理失败');
  
  document.getElementById('uploadArea').style.display = 'block';
  document.getElementById('progressContainer').style.display = 'none';
}

/**
 * 处理Word模板填充
 */
async function handleFillWordTemplate() {
  // 获取Base和Lisan JSON文件路径
  const baseJsonFileInput = document.getElementById('baseJsonFile');
  const lisanJsonFileInput = document.getElementById('lisanJsonFile');
  
  if (!pyAPI) {
    addLog('Python API 不可用，无法执行填充数据功能', 'error');
    console.error('Python API 不可用');
    return;
  }
  
  const baseJsonFilePath = baseJsonFileInput.value.trim();
  const lisanJsonFilePath = lisanJsonFileInput.value.trim();
  
  console.log('Base JSON文件路径:', baseJsonFilePath);
  console.log('Lisan JSON文件路径:', lisanJsonFilePath);
  
  // 检查Base数据和Lisan数据文件至少存在一个
  if (!baseJsonFilePath && !lisanJsonFilePath) {
    const errorMessage = '请至少选择一个数据文件（Base JSON文件 或 Lisan JSON文件）';
    console.log(errorMessage, 'error');
    
    // 使用Element UI消息提示
    if (window.ELEMENT && window.ELEMENT.Message) {
      window.ELEMENT.Message.error(errorMessage);
    } else if (window.$message) {
      window.$message.error(errorMessage);
    } else {
      alert(errorMessage);
    }
    return;
  }
  
  // 获取Word模板路径
  let templatePath = '';
  
  // 验证文件路径是否存在（第二次验证）
  try {
    if (baseJsonFilePath && window.fileAPI && window.fileAPI.checkFileExists) {
      addLog('使用checkFileExists验证Base文件...', 'info');
      const baseExists = await window.fileAPI.checkFileExists(baseJsonFilePath);
      console.log('Base文件checkFileExists结果:', baseExists);
      if (!baseExists) {
        throw new Error(`Base JSON文件不存在: ${baseJsonFilePath}`);
      }
    } else {
      addLog('跳过Base文件checkFileExists验证（方法不可用）', 'warning');
    }
    
    if (lisanJsonFilePath && window.fileAPI && window.fileAPI.checkFileExists) {
      addLog('使用checkFileExists验证Lisan文件...', 'info');
      const lisanExists = await window.fileAPI.checkFileExists(lisanJsonFilePath);
      console.log('Lisan文件checkFileExists结果:', lisanExists);
      if (!lisanExists) {
        throw new Error(`Lisan JSON文件不存在: ${lisanJsonFilePath}`);
      }
    } else {
      addLog('跳过Lisan文件checkFileExists验证（方法不可用）', 'warning');
    }
    console.log('Base JSON文件路径:', baseJsonFilePath);
    console.log('Lisan JSON文件路径:', lisanJsonFilePath);
    
    // 处理Word模板文件
    const wordTemplateFileInput = document.getElementById('wordTemplateFile');
    if (wordTemplateFileInput && wordTemplateFileInput.value.trim()) {
      templatePath = wordTemplateFileInput.value.trim();
      console.log('Word模板文件路径:', templatePath);
      addLog(`Word模板文件路径: ${templatePath}`, 'info');
    } else {
      console.log('未选择Word模板文件，将使用默认模板');
      addLog('未选择Word模板文件，将使用默认模板', 'info');
    }
  } catch (error) {
    addLog(`获取文件路径失败: ${error.message}`, 'error');
    console.error('获取文件路径失败:', error);
    return;
  }
  
  // 清除之前的提示信息
  clearWordTemplateAlerts();
  
  // 显示加载中提示
  createWordTemplateAlert('info', '正在处理Word模板，请稍后...', false);
  
  // Word模板文件路径已在上面处理
  addLog(`Word模板路径处理完成: ${templatePath}`, 'info');
  console.log('准备调用Python脚本，参数:', {
    baseJsonFilePath,
    lisanJsonFilePath,
    templatePath
  });
  
  const outputPath = document.getElementById('wordOutputPath').value.trim();
  
  // 显示加载提示和进度条
  document.getElementById('wordTemplateProgressContainer').style.display = 'block';
  document.getElementById('wordTemplateProgressBar').style.width = '10%';
  document.getElementById('wordTemplateProgressText').textContent = '10%';
  
  // 修改按钮状态，防止重复点击
  const fillTemplateBtn = document.getElementById('fillTemplateBtn');
  const originalBtnText = fillTemplateBtn.innerHTML;
  fillTemplateBtn.innerHTML = '<i class="bi bi-hourglass-split me-1"></i> 请稍后...';
  fillTemplateBtn.disabled = true;
  
  addLog('开始填充Word模板...', 'info');
  addLog(`Base JSON文件路径: ${baseJsonFilePath}`, 'info');
  addLog(`Lisan JSON文件路径: ${lisanJsonFilePath}`, 'info');
  if (templatePath) {
    addLog(`Word模板路径: ${templatePath}`, 'info');
  } else {
    addLog('未指定Word模板路径，将使用默认模板', 'info');
  }
  if (outputPath) {
    addLog(`输出文件路径: ${outputPath}`, 'info');
  } else {
    addLog('未指定输出路径，将在JSON文件同目录下创建', 'info');
  }
  
  // 设置Python日志监听器
  const pythonLogHandler = (logData) => {
    // 处理Python脚本的实时日志输出
    const logMessage = logData.data.trim();
    if (logMessage) {
      // 根据日志类型设置不同的日志级别
      const logLevel = logData.type === 'stderr' ? 'error' : 'info';
      addLog(`[Python] ${logMessage}`, logLevel);
    }
  };
  
  const pythonEndHandler = (endData) => {
    addLog(`Python脚本执行结束，退出码: ${endData.code}`, endData.success ? 'info' : 'error');
    // 移除监听器
    pyAPI.removePythonLogListeners();
  };
  
  const pythonErrorHandler = (errorData) => {
    addLog(`Python进程错误: ${errorData.error}`, 'error');
    // 移除监听器
    pyAPI.removePythonLogListeners();
  };
  
  // 注册Python日志监听器
  pyAPI.onPythonLogOutput(pythonLogHandler);
  pyAPI.onPythonProcessEnded(pythonEndHandler);
  pyAPI.onPythonProcessError(pythonErrorHandler);
  
  try {
    // 更新进度条到10%
    document.getElementById('wordTemplateProgressBar').style.width = '10%';
    document.getElementById('wordTemplateProgressText').textContent = '10%';
    console.log('开始调用Python依赖检查脚本');
    
    // 首先检查和安装Python依赖
    addLog('调用install_dependencies.py脚本...', 'info');
    const dependencyResult = await pyAPI.runpyfile({
      scriptPath: './install_dependencies.py',
      pluginName: 'sofaData-process',
      args: []
    });
    
    console.log('Python依赖检查结果:', dependencyResult);
    
    if (!dependencyResult.success) {
      addLog(`依赖检查失败: ${dependencyResult.error}`, 'error');
      createWordTemplateAlert('danger', `依赖检查失败: ${dependencyResult.error}`, false);
      return;
    }
    
    // 解析依赖检查结果
    console.log('依赖检查原始数据:', dependencyResult.data);
    
    try {
      // 检查返回的数据是否为有效JSON
      if (typeof dependencyResult.data === 'string' && dependencyResult.data.trim().startsWith('{')) {
        const depData = JSON.parse(dependencyResult.data);
        console.log('解析后的依赖数据:', depData);
        if (!depData.success) {
          createWordTemplateAlert('danger', `依赖安装失败: ${depData.error}`, false);
          return;
        }
        console.log('Python依赖检查完成', 'success');
      } else {
        // 如果不是JSON格式，假设依赖检查成功（可能是直接输出的文本）
        console.log('依赖检查返回非JSON格式数据，跳过解析');
      }
    } catch (e) {
      console.error('解析依赖检查结果失败:', e);
      console.log(`解析依赖检查结果失败，但继续执行: ${e.message}`, 'warning');
      // 不返回，继续执行后续步骤
    }
    
    // 更新进度条到30%
    document.getElementById('wordTemplateProgressBar').style.width = '30%';
    document.getElementById('wordTemplateProgressText').textContent = '30%';
    addLog('正在调用Python脚本处理Word模板...', 'info');
    
    // 调用Python脚本，传递Base和Lisan JSON文件路径、模板路径和输出路径
    const args = [baseJsonFilePath, lisanJsonFilePath];
    if (templatePath) args.push(templatePath);
    if (outputPath) args.push(outputPath);
    
    addLog(`准备调用Python脚本，参数: ${args.join(', ')}`, 'info');
    
    // 使用相对路径，并提供插件名称以便正确解析
    addLog('开始执行Python脚本...', 'info');
    console.log('调用Python脚本的完整参数:', {
      scriptPath: './fill_word_template.py',
      pluginName: 'sofaData-process',
      args: args
    });
    const result = await pyAPI.runpyfile({
      scriptPath: './fill_word_template.py',
      pluginName: 'sofaData-process',
      args: args
    });
    
    addLog(`Python脚本执行完成，返回结果: ${JSON.stringify(result)}`, 'info');
     
    // 更新进度条到70%
    document.getElementById('wordTemplateProgressBar').style.width = '70%';
    document.getElementById('wordTemplateProgressText').textContent = '70%';

    if (result.success) {
      try {
        // 更新进度条到90%
        document.getElementById('wordTemplateProgressBar').style.width = '90%';
        document.getElementById('wordTemplateProgressText').textContent = '90%';
        addLog('正在解析返回数据...', 'info');
        
        // 检查返回数据是否为空
        if (!result.data) {
          addLog('Python脚本返回的数据为空', 'error');
          createWordTemplateAlert('danger', 'Python脚本返回的数据为空', false);
          return;
        }
        
        addLog(`Python脚本返回的原始数据: ${result.data}`, 'info');
        
        let parsedData;
        try {
          parsedData = JSON.parse(result.data);
          addLog(`成功解析JSON数据: ${JSON.stringify(parsedData)}`, 'info');
        } catch (parseError) {
          addLog(`JSON解析失败: ${parseError.message}`, 'error');
          addLog(`尝试解析的数据: ${result.data}`, 'error');
          createWordTemplateAlert('danger', `JSON解析失败: ${parseError.message}`, false);
          return;
        }
        
        if (parsedData.success) {
          addLog('Word模板填充成功！', 'success');
          
          if (!parsedData.output_file) {
            addLog('警告：返回数据中缺少输出文件路径', 'warning');
          }
          
          // 显示成功提示
          createWordTemplateAlert('success', `Word文档已成功生成: ${parsedData.output_file || '未知路径'}`);
          
          // 显示结果区域
          document.getElementById('wordTemplateResultSection').style.display = 'block';
          document.getElementById('wordTemplateResultMessage').textContent = `Word文档已成功生成: ${parsedData.output_file || '未知路径'}`;
          
          // 为重置按钮添加事件监听器
          const resetBtn = document.getElementById('wordTemplateResetBtn');
          if (resetBtn) {
            resetBtn.addEventListener('click', resetWordTemplateForm);
          }
        } else {
          addLog(`Word模板填充失败: ${parsedData.error || '未知错误'}`, 'error');
          
          // 显示错误提示
          createWordTemplateAlert('danger', parsedData.error || '未知错误', false);
        }
      } catch (e) {
        addLog(`处理返回数据时发生异常: ${e.message}`, 'error');
        addLog(`异常堆栈: ${e.stack}`, 'error');
        
        // 显示错误提示
        createWordTemplateAlert('danger', `处理返回数据时发生异常: ${e.message}`, false);
      }
    } else {
      addLog(`Python脚本执行失败: ${result.error || '未知错误'}`, 'error');
      
      // 显示错误提示
      createWordTemplateAlert('danger', result.error || '未知错误', false);
    }
  } catch (error) {
    addLog(`调用Python脚本时出错: ${error.message}`, 'error');
    createWordTemplateAlert('danger', `调用Python脚本时出错: ${error.message}`, false);
  } finally {
    // 确保移除Python日志监听器
    pyAPI.removePythonLogListeners();
    
    // 恢复按钮状态
    fillTemplateBtn.innerHTML = originalBtnText;
    fillTemplateBtn.disabled = false;
    
    // 更新进度条到100%
    document.getElementById('wordTemplateProgressBar').style.width = '100%';
    document.getElementById('wordTemplateProgressText').textContent = '100%';
    addLog('处理完成，进度100%', 'info');
    
    // 延迟后隐藏进度条（给用户时间看到完成状态）
    addLog('延迟3秒后隐藏进度条', 'info');
    setTimeout(() => {
      document.getElementById('wordTemplateProgressContainer').style.display = 'none';
      addLog('进度条已隐藏', 'info');
      
      // 确保结果区域可见（如果有错误信息）
      const resultSection = document.getElementById('wordTemplateResultSection');
      if (resultSection && resultSection.style.display === 'none') {
        const alerts = document.querySelectorAll('.alert');
        if (alerts.length > 0) {
          resultSection.style.display = 'block';
          addLog('显示结果区域', 'info');
        }
      }
    }, 3000); // 延长到3秒，确保用户能看到进度条完成状态
  }
}

/**
 * 清除Word模板填充页面的提示信息
 */
function clearWordTemplateAlerts() {
  const alertContainer = document.getElementById('wordTemplateResultSection');
  if (alertContainer) {
    alertContainer.style.display = 'none';
  }
}

/**
 * 创建Word模板填充页面的提示信息
 * @param {string} type - 提示类型 (success, info, warning, danger)
 * @param {string} message - 提示信息
 * @param {boolean} showResultSection - 是否显示结果区域
 */
function createWordTemplateAlert(type, message, showResultSection = true) {
  const resultSection = document.getElementById('wordTemplateResultSection');
  const resultMessage = document.getElementById('wordTemplateResultMessage');
  
  if (resultSection && resultMessage) {
    resultMessage.className = `alert alert-${type}`;
    resultMessage.textContent = message;
    
    if (showResultSection) {
      resultSection.style.display = 'block';
    }
  }
}

/**
 * 重置Word模板填充表单
 */
function resetWordTemplateForm() {
  // 清空输入框
  document.getElementById('baseJsonFile').value = '';
  document.getElementById('lisanJsonFile').value = '';
  // 清空文件选择器
  const wordTemplateFileInput = document.getElementById('wordTemplateFile');
  if (wordTemplateFileInput) {
    wordTemplateFileInput.value = '';
  }
  document.getElementById('wordOutputPath').value = '';
  
  // 隐藏结果区域和进度条
  document.getElementById('wordTemplateResultSection').style.display = 'none';
  document.getElementById('wordTemplateProgressContainer').style.display = 'none';
  
  // 重置进度条
  document.getElementById('wordTemplateProgressBar').style.width = '0%';
  document.getElementById('wordTemplateProgressText').textContent = '0%';
  
  addLog('已重置Word模板填充表单', 'info');
}

/**
 * 设置Python脚本日志监听器
 * 监听来自主进程的Python脚本输出
 */
// 检查Python环境启动函数
async function checkPythonEnvironmentOnStartup() {
  try {
    addLog('开始检查Python环境...', 'info');
    
    // 调用pythonEnvironmentService的checkAndDownloadPythonEnvironment方法
    if (pyAPI && pyAPI.checkAndDownloadPythonEnvironment) {
      const result = await pyAPI.checkAndDownloadPythonEnvironment('sofaData-process');
      
      if (result.success && result.installed) {
        addLog(`Python环境检查完成 - 版本: ${result.version}, pip: ${result.pipInstalled ? '已安装' : '未安装'}`, 'success');
      } else {
        addLog(`Python环境检查失败: ${result.message}`, 'error');
      }
    } else {
      addLog('pyAPI不可用，无法检查Python环境', 'error');
    }
  } catch (error) {
    addLog(`Python环境检查出错: ${error.message}`, 'error');
    console.error('Python环境检查出错:', error);
  }
}

function setupPythonLogListeners() {
  // 检查pyAPI是否可用
  if (!pyAPI) {
    addLog('[Python] pyAPI不可用，无法设置Python日志监听器', 'error');
    return;
  }
  
  // 监听Python脚本的stdout和stderr输出
  pyAPI.onPythonLogOutput((data) => {
    if (data.type === 'stdout') {
      // 处理标准输出，通常是正常的日志信息
      const message = data.data.trim();
      if (message) {
        // 根据消息内容判断日志级别
        let logType = 'info';
        if (message.includes('[ERROR]') || message.includes('ERROR') || message.includes('Failed')) {
          logType = 'error';
        } else if (message.includes('[SUCCESS]') || message.includes('SUCCESS') || message.includes('[OK]')) {
          logType = 'success';
        } else if (message.includes('[INSTALL]') || message.includes('Installing')) {
          logType = 'warning';
        }
        
        addLog(`[Python] ${message}`, logType);
      }
    } else if (data.type === 'stderr') {
      // 处理错误输出
      const errorMessage = data.data.trim();
      if (errorMessage) {
        addLog(`[Python Error] ${errorMessage}`, 'error');
      }
    }
  });
  
  // 监听Python进程结束事件
  pyAPI.onPythonProcessEnded((data) => {
    if (data.success) {
      addLog('[Python] 脚本执行完成', 'success');
    } else {
      addLog(`[Python] 脚本执行失败，退出码: ${data.code}`, 'error');
    }
  });
  
  // 监听Python进程错误事件
  pyAPI.onPythonProcessError((data) => {
    addLog(`[Python] 进程启动失败: ${data.error}`, 'error');
  });
  
  // 监听Python环境状态事件
  pyAPI.onPythonEnvironmentStatus((statusData) => {
    const { status, message, progress } = statusData;
    
    let logType = 'info';
    if (status === 'downloading') {
      logType = 'info';
    } else if (status === 'installing') {
      logType = 'warning';
    } else if (status === 'completed') {
      logType = 'success';
    }
    
    addLog(`[Python环境] ${message}`, logType);
    
    // 更新环境检查提示
    updatePythonEnvironmentAlert(status, message, progress);
  });  
  addLog('Python日志监听器已设置', 'info');
}

/**
 * 处理包含'after'的CSV文件
 */
async function handleProcessAfterFile() {
  // 检查是否选择了Excel模板文件
  const excelTemplateFile = document.getElementById('excelTemplateFile').files[0];
  if (!excelTemplateFile) {
    addLog('请选择Excel文件', 'error', true);
    return;
  }
  
  // 检查是否设置了起始帧数
  const startValue = document.getElementById('afterStartValue').value;
  if (!startValue || startValue < 1) {
    addLog('请设置有效的起始帧数', 'error', true);
    return;
  }
  
  if (currentCSVFiles.length === 0) {
    addLog('没有可处理的CSV文件', 'error', true);
    return;
  }
  
  try {
    addLog('开始处理After文件...', 'info', true);
    
    // 显示进度条
    document.getElementById('progressContainer').style.display = 'block';
    document.getElementById('progressBar').style.width = '10%';
    document.getElementById('progressText').textContent = '10%';
    
    // 读取Excel文件
    const excelArrayBuffer = await excelTemplateFile.arrayBuffer();
    const workbook = XLSX.read(excelArrayBuffer, { type: 'array' });
    
    addLog('Excel模板文件读取成功', 'success');
    document.getElementById('progressBar').style.width = '30%';
    document.getElementById('progressText').textContent = '30%';
    
    // 检查是否存在'一小时后'sheet
    if (!workbook.Sheets['一小时后']) {
      addLog('Excel模板中未找到"一小时后"工作表', 'error', true);
      return;
    }
    
    // 处理CSV文件数据（按区域分别提取数据）
    let allRegionData = {}; // 按区域存储数据
    let globalFrameNumber = parseInt(startValue); // 全局帧号，为所有数据连续递增
    
    // 初始化所有区域的数据数组
    for (let regionNum = 2; regionNum <= 10; regionNum++) {
      allRegionData[`Region ${regionNum}`] = [];
    }
    
    for (let i = 0; i < currentCSVFiles.length; i++) {
      const file = currentCSVFiles[i];
      addLog(`正在处理文件 ${i + 1}/${currentCSVFiles.length}: ${file.name}`, 'info');
      
      const csvText = await file.text();
      const lines = csvText.split('\n');
      
      // 遍历CSV的每一行，查找各个Region的数据
      for (let j = 1; j < lines.length; j++) { // 跳过标题行
        const line = lines[j].trim();
        if (!line) continue;
        
        const columns = line.split(',');
        if (columns.length < 7) continue; // 确保有足够的列
        
        const regionName = columns[0].trim(); // 第一列是Region名称
        
        // 检查是否是我们需要的Region（Region 2到Region 10）
        for (let regionNum = 2; regionNum <= 10; regionNum++) {
          if (regionName === `Region ${regionNum}`) {
            const maxPressure = parseFloat(columns[2]) || 0; // C列（索引2）
            const avgPressure = parseFloat(columns[6]) || 0; // G列（索引6）
            const contactArea = parseFloat(columns[8]) || 0; // I列（索引8）
            
            allRegionData[regionName].push({
              frameNumber: globalFrameNumber,
              maxPressure: maxPressure,
              avgPressure: avgPressure,
              contactArea: contactArea
            });
            
            break;
          }
        }
      }
      
      // 每处理完一个CSV文件，全局帧号递增1
      globalFrameNumber++;
      
      const progress = 30 + (i + 1) / currentCSVFiles.length * 40;
      document.getElementById('progressBar').style.width = `${progress}%`;
      document.getElementById('progressText').textContent = `${Math.round(progress)}%`;
    }
    
    // 统计总数据量
    let totalDataCount = 0;
    for (const region in allRegionData) {
      totalDataCount += allRegionData[region].length;
      if (allRegionData[region].length > 0) {
        addLog(`${region}: ${allRegionData[region].length} 行数据`, 'info');
      }
    }
    addLog(`共提取 ${totalDataCount} 行数据`, 'success');
    
    // 将数据写入'一小时后'sheet（使用与七区完全相同的逻辑）
    const oneHourSheet = workbook.Sheets['一小时后'];
    if (!oneHourSheet) {
      throw new Error('Excel中未找到"一小时后"工作表');
    }
    
    addLog('开始写入数据到"一小时后"工作表...', 'info');
    
    // 使用与handleExtractData相同的oneHourRegionConfigs配置
    const oneHourRegionConfigs = {
      'Region 4': { sheetName: '一小时后', maxPressureCol: 'B', avgPressureCol: 'C' },
      'Region 5': { sheetName: '一小时后', maxPressureCol: 'D', avgPressureCol: 'E' },
      'Region 6': { sheetName: '一小时后', maxPressureCol: 'F', avgPressureCol: 'G' },
      'Region 7': { sheetName: '一小时后', maxPressureCol: 'H', avgPressureCol: 'I' },
      'Region 8': { sheetName: '一小时后', maxPressureCol: 'J', avgPressureCol: 'K' },
      'Region 9': { sheetName: '一小时后', maxPressureCol: 'L', avgPressureCol: 'M' },
      'Region 10': { sheetName: '一小时后', maxPressureCol: 'N', avgPressureCol: 'O' }
    };
    
    // 使用分块处理方式写入数据，避免长时间阻塞主线程
    const CHUNK_SIZE = 100; // 每次处理100行
    
    // 处理'一小时后'各区域数据的函数
    function processOneHourRegionData(sheet, region, config, regionData, startIndex, endIndex, columnAConfig) {
      return new Promise(resolve => {
        setTimeout(() => {
          if (!regionData || regionData.length === 0 || startIndex >= regionData.length) {
            resolve();
            return;
          }
          
          const end = Math.min(endIndex, regionData.length);
          let rowIndex = startIndex + 2; // 从第2行开始写入
          
          for (let i = startIndex; i < end; i++) {
            const item = regionData[i];
            
            // 写入A列数据（帧数）- 使用与writeDataToTemplate相同的逻辑
            if (columnAConfig && columnAConfig.start !== null) {
              const globalIndex = startIndex + (i - startIndex);
              const columnAValue = columnAConfig.start + globalIndex;
              XLSX.utils.sheet_add_aoa(sheet, [[columnAValue]], { origin: `A${rowIndex}` });
            }
            
            // 写入最大压力值（C列数据写入对应的maxPressureCol）
            if (config.maxPressureCol) {
              XLSX.utils.sheet_add_aoa(sheet, [[item.maxPressure]], { origin: `${config.maxPressureCol}${rowIndex}` });
            }
            
            // 写入平均值（G列数据写入对应的avgPressureCol）
            if (config.avgPressureCol) {
              XLSX.utils.sheet_add_aoa(sheet, [[item.avgPressure]], { origin: `${config.avgPressureCol}${rowIndex}` });
            }
            
            // 写入接触面积（如果配置了contactAreaCol）
            if (config.contactAreaCol) {
              XLSX.utils.sheet_add_aoa(sheet, [[item.contactArea]], { origin: `${config.contactAreaCol}${rowIndex}` });
            }
            
            rowIndex++;
          }
          
          resolve();
        }, 0);
      });
    }
    
    // 分块处理数据写入（遍历所有区域）
    document.getElementById('progressBar').style.width = '70%';
    document.getElementById('progressText').textContent = '70%';
    
    let processedRegions = 0;
    const totalRegions = Object.keys(oneHourRegionConfigs).length;
    
    // 遍历所有区域配置
    for (const region in oneHourRegionConfigs) {
      const config = oneHourRegionConfigs[region];
      const regionData = allRegionData[region] || [];
      
      if (regionData.length > 0) {
        addLog(`开始写入${region}数据到${config.sheetName}sheet，共${regionData.length}行`, 'info');
        
        // 分块处理当前区域的数据
        for (let i = 0; i < regionData.length; i += CHUNK_SIZE) {
          // 创建columnAConfig对象，使用起始帧数
          const columnAConfig = { start: parseInt(startValue) };
          await processOneHourRegionData(oneHourSheet, region, config, regionData, i, i + CHUNK_SIZE, columnAConfig);
          
          // 使用requestAnimationFrame确保UI更新
          if (i + CHUNK_SIZE < regionData.length) {
            await new Promise(resolve => requestAnimationFrame(resolve));
          }
        }
        
        addLog(`完成${region}数据写入，共${regionData.length}行`, 'success');
      } else {
        addLog(`${region}没有数据需要写入`, 'info');
      }
      
      processedRegions++;
      
      // 更新进度
      const progress = 70 + Math.floor((processedRegions / totalRegions) * 15);
      document.getElementById('progressBar').style.width = `${Math.min(progress, 85)}%`;
      document.getElementById('progressText').textContent = `${Math.min(progress, 85)}%`;
    }
    
    addLog(`成功写入 ${totalDataCount} 行数据到'一小时后'工作表`, 'success');
    
    // 处理'一小时后'sheet中max行数据：在所有数据写入完成后，空一行，然后在A列写入'初始max'
    try {
      addLog('处理"一小时后"sheet中max行数据', 'info');
      const oneHourSheetForMax = workbook.Sheets['一小时后'];
      if (oneHourSheetForMax) {
        const range = XLSX.utils.decode_range(oneHourSheetForMax['!ref']);
        
        // 找到最后一行有数据的行号
        let lastDataRow = range.s.r; // 从标题行开始
        for (let R = range.s.r + 1; R <= range.e.r; ++R) {
          // 检查A列是否有数据（排除max行和初始max行）
          const cellAddressA = XLSX.utils.encode_cell({ c: 0, r: R });
          const cellA = oneHourSheetForMax[cellAddressA];
          if (cellA && cellA.v !== undefined && cellA.v !== null) {
            const cellValue = cellA.v.toString().toLowerCase();
            if (cellValue !== 'max' && cellValue !== '初始max') {
              lastDataRow = R;
            }
          }
        }
        
        // 计算B到P列的最大值 (列索引1到15)，只计算数据行，不包括max行
        const maxValues = {};
        for (let col = 1; col <= 15; col++) { // B列(1)到P列(15)
          maxValues[col] = null;
          for (let R = range.s.r + 1; R <= lastDataRow; ++R) { // 只计算到最后一行数据
            const cellAddress = XLSX.utils.encode_cell({ c: col, r: R });
            const cell = oneHourSheetForMax[cellAddress];
            if (cell && cell.v !== undefined && cell.v !== null) {
              const value = parseFloat(cell.v);
              if (!isNaN(value)) {
                if (maxValues[col] === null || value > maxValues[col]) {
                  maxValues[col] = value;
                }
              }
            }
          }
        }
        
        // 在最后一行数据后空一行，然后写入'初始max'行
        const initialMaxRowIndex = lastDataRow + 2; // 空一行后的第二行
        
        // 在A列写入'初始max'
        const initialMaxCellA = XLSX.utils.encode_cell({ c: 0, r: initialMaxRowIndex });
        oneHourSheetForMax[initialMaxCellA] = {
          v: '初始max',
          t: 's'
        };
        
        // 获取七区max行数据写入初始max行（而不是使用一小时后sheet自身的最大值）
        let sevenRegionMaxValues = {};
        try {
          const sevenRegionSheet = workbook.Sheets['七区'];
          if (sevenRegionSheet) {
            const sevenRange = XLSX.utils.decode_range(sevenRegionSheet['!ref']);
            // 查找A列为'max'的行
            for (let R = sevenRange.s.r + 1; R <= sevenRange.e.r; ++R) {
              const cellAddressA = XLSX.utils.encode_cell({ c: 0, r: R });
              const cellA = sevenRegionSheet[cellAddressA];
              if (cellA && cellA.v && cellA.v.toString().toLowerCase() === 'max') {
                // 获取B到O列的数据
                for (let col = 1; col <= 14; col++) {
                  const cellAddress = XLSX.utils.encode_cell({ c: col, r: R });
                  const cell = sevenRegionSheet[cellAddress];
                  if (cell && cell.v !== undefined && cell.v !== null) {
                    sevenRegionMaxValues[col] = parseFloat(cell.v);
                  }
                }
                break;
              }
            }
          }
        } catch (sevenRegionError) {
          addLog(`获取七区max行数据时出错: ${sevenRegionError.message}`, 'warning');
        }
        
        // 写入B到O列的数据（使用七区max行数据作为初始max行）
        for (let col = 1; col <= 14; col++) { // B列(1)到O列(14)
          if (sevenRegionMaxValues[col] !== undefined && sevenRegionMaxValues[col] !== null) {
            const cellAddress = XLSX.utils.encode_cell({ c: col, r: initialMaxRowIndex });
            oneHourSheetForMax[cellAddress] = {
              v: sevenRegionMaxValues[col],
              t: 'n'
            };
          }
        }
        
        // 计算除初始max行外的B到O列最大值（用于一小时后max行）
        const oneHourMaxValues = {};
        for (let col = 1; col <= 14; col++) { // B列(1)到O列(14)
          oneHourMaxValues[col] = null;
          for (let R = range.s.r + 1; R <= lastDataRow; ++R) { // 只计算到最后一行数据
            const cellAddress = XLSX.utils.encode_cell({ c: col, r: R });
            const cell = oneHourSheetForMax[cellAddress];
            if (cell && cell.v !== undefined && cell.v !== null) {
              const value = parseFloat(cell.v);
              if (!isNaN(value)) {
                if (oneHourMaxValues[col] === null || value > oneHourMaxValues[col]) {
                  oneHourMaxValues[col] = value;
                }
              }
            }
          }
        }
        
        // 在初始max行下面写入'一小时后max'行
        const oneHourMaxRowIndex = initialMaxRowIndex + 1;
        
        // 在A列写入'一小时后max'
        const oneHourMaxCellA = XLSX.utils.encode_cell({ c: 0, r: oneHourMaxRowIndex });
        oneHourSheetForMax[oneHourMaxCellA] = {
          v: '一小时后max',
          t: 's'
        };
        
        // 写入B到O列的最大值（一小时后max行）
        for (let col = 1; col <= 14; col++) { // B列(1)到O列(14)
          if (oneHourMaxValues[col] !== null) {
            const cellAddress = XLSX.utils.encode_cell({ c: col, r: oneHourMaxRowIndex });
            oneHourSheetForMax[cellAddress] = {
              v: oneHourMaxValues[col],
              t: 'n'
            };
          }
        }
        
        // 在一小时后max行下面写入百分比计算行
        const percentageRowIndex = oneHourMaxRowIndex + 1;
        
        // 在A列写入标识
        const percentageCellA = XLSX.utils.encode_cell({ c: 0, r: percentageRowIndex });
        oneHourSheetForMax[percentageCellA] = {
          v: '变化百分比',
          t: 's'
        };
        
        // 计算并写入B到O列的百分比：(一小时后max - 初始max) / 初始max
        // 使用七区数据作为初始max值进行百分比计算
        for (let col = 1; col <= 14; col++) { // B列(1)到O列(14)
          if (sevenRegionMaxValues[col] !== undefined && sevenRegionMaxValues[col] !== null && 
              oneHourMaxValues[col] !== null && sevenRegionMaxValues[col] !== 0) {
            const percentage = (oneHourMaxValues[col] - sevenRegionMaxValues[col]) / sevenRegionMaxValues[col];
            const cellAddress = XLSX.utils.encode_cell({ c: col, r: percentageRowIndex });
            oneHourSheetForMax[cellAddress] = {
              v: percentage,
              t: 'n',
              z: '0.00%' // 设置为百分比格式
            };
          }
        }
        
        // 更新工作表范围
        const newRange = XLSX.utils.encode_range({
          s: { c: range.s.c, r: range.s.r },
          e: { c: Math.max(range.e.c, 14), r: percentageRowIndex }
        });
        oneHourSheetForMax['!ref'] = newRange;
        
        const colNames = ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'];
        addLog(`在"一小时后"sheet第${initialMaxRowIndex+1}行写入初始max行数据，第${oneHourMaxRowIndex+1}行写入一小时后max行数据，第${percentageRowIndex+1}行写入变化百分比，${colNames.join(',')}列`, 'success');
      }
    } catch (maxError) {
      addLog(`处理"一小时后"sheet max行时出错: ${maxError.message}`, 'warning');
    }
    
    document.getElementById('progressBar').style.width = '90%';
    document.getElementById('progressText').textContent = '90%';
    
    // 使用saveProcessedFile函数保存文件到与普通CSV处理相同的目录
    try {
      // 生成基于源文件名的文件名
      let baseFileName = 'after_files';
      if (currentCSVFiles.length > 0) {
        // 如果只有一个文件，使用该文件名；如果有多个文件，使用第一个文件名或通用名称
        if (currentCSVFiles.length === 1) {
          baseFileName = currentCSVFiles[0].name.replace(/\.(csv|CSV)$/, '');
        } else {
          // 多个文件时，可以使用第一个文件名作为基础，或者使用通用名称
          baseFileName = currentCSVFiles[0].name.replace(/\.(csv|CSV)$/, '') + '_batch';
        }
      }
      const fileName = `${baseFileName}_processed`;
      const savedFilePath = await saveProcessedFile(workbook, '', fileName);
      
      document.getElementById('progressBar').style.width = '100%';
      document.getElementById('progressText').textContent = '100%';
      
      addLog('After文件处理完成，Excel文件已保存', 'success', true);
      
      // 显示结果
      showResult(savedFilePath);
    } catch (saveError) {
      addLog(`保存文件时出错: ${saveError.message}`, 'error', true);
      throw saveError;
    }
    
    // 发送监控数据
    try {
      const userSettings = await electronAPI.getUserSettings();
      
      // 构建监控数据
      const monitoringData = {
        user_name: userSettings.email?.split('@')[0] || 'unknown',
        user_location: userSettings.site || 'unknown',
        rpa_id: "140",
        rpa_name: manifest.name,
        rpa_version: manifest.version,
        occurrence: new Date().toLocaleString('en-US', {
          weekday: 'short',
          day: '2-digit',
          month: 'short',
          year: 'numeric',
          hour: '2-digit',
          minute: '2-digit',
          second: '2-digit',
          hour12: false
        }),
        info: "人体工学数据处理 - After文件",
        extra: `处理了${currentCSVFiles.length}个CSV文件`
      };
      
      // 发送监控数据
      console.log('准备发送的监控数据：', monitoringData);
      const monitoringResult = await sendMonitoringData([monitoringData]);
      
      if (monitoringResult.success) {
        console.log(`监控数据发送成功 - After文件处理: ${currentCSVFiles.length}个文件`);
      } else {
        console.log(`监控数据发送失败 - After文件处理, 错误信息: ${monitoringResult.message}`);
      }
    } catch (monitoringError) {
      console.error(`发送监控数据时出错: ${monitoringError.message}`);
    }
    
    // 注意：结果显示已在saveProcessedFile成功后通过showResult函数处理
    
  } catch (error) {
    addLog(`处理After文件时出错: ${error.message}`, 'error', true);
    console.error('处理After文件错误:', error);
  }
}

// 离散系数计算相关函数
let cvFile = null;
let cvOriginalFileName = null; // 保存原始CSV文件名

// 处理CSV文件上传
function handleCVFileUpload(file) {
  if (!file.name.toLowerCase().endsWith('.csv')) {
    addLog('错误: 请上传CSV文件', 'error');
    return;
  }
  
  cvFile = file;
  cvOriginalFileName = file.name; // 保存原始文件名
  const cvFileName = document.getElementById('cv-file-name');
  const cvSelectedFile = document.getElementById('cv-selected-file');
  
  if (cvFileName && cvSelectedFile) {
    cvFileName.textContent = file.name;
    cvSelectedFile.style.display = 'block';
  }
  document.getElementById('cvFrameIndexContainer').style.display = 'block';
  document.getElementById('cvCalculateContainer').style.display = 'block';
  
  // 确保计算按钮的事件监听器已绑定
  const calculateCVBtn = document.getElementById('calculateCVBtn');
  if (calculateCVBtn) {
    // 移除可能存在的旧事件监听器
    calculateCVBtn.removeEventListener('click', handleCalculateCV);
    // 添加新的事件监听器
    calculateCVBtn.addEventListener('click', handleCalculateCV);
    console.log('离散系数计算按钮事件监听器已绑定');
  } else {
    console.error('未找到离散系数计算按钮');
  }
  
  addLog(`已选择CSV文件: ${file.name}`, 'info');
}

// 处理离散系数计算
async function handleCalculateCV() {
  console.log('handleCalculateCV函数被调用');
  addLog('开始处理离散系数计算请求...', 'info');
  
  if (!cvFile) {
    addLog('请先上传CSV文件', 'error');
    console.error('cvFile为空，无法进行计算');
    return;
  }
  
  console.log('CSV文件已准备就绪:', cvFile.name);
  
  // 显示进度条
  document.getElementById('cvProgressContainer').style.display = 'block';
  document.getElementById('cvProgressBar').style.width = '10%';
  document.getElementById('cvProgressText').textContent = '10%';
  
  // 修改按钮状态
  const calculateBtn = document.getElementById('calculateCVBtn');
  const originalBtnText = calculateBtn.innerHTML;
  calculateBtn.innerHTML = '<i class="bi bi-hourglass-split me-1"></i> 计算中...';
  calculateBtn.disabled = true;
  
  try {
    addLog('开始计算离散系数...', 'info');
    
    // 更新进度条到30%
    document.getElementById('cvProgressBar').style.width = '30%';
    document.getElementById('cvProgressText').textContent = '30%';
    
    // 获取用户输入的起始帧数和计算帧数
    const startFrameInput = document.getElementById('startFrameInput');
    const frameIndexInput = document.getElementById('frameIndexInput');
    const startFrame = startFrameInput ? parseInt(startFrameInput.value) || 1 : 1;
    const calculateFrame = frameIndexInput ? parseInt(frameIndexInput.value) || 1 : 1;
    
    if (startFrame < 1) {
      addLog('起始帧数必须大于等于1', 'error');
      return;
    }
    
    if (calculateFrame < 1) {
      addLog('计算帧数必须大于等于1', 'error');
      return;
    }
    
    // 计算实际的Frame Index: n - x + 1
    const frameIndex = calculateFrame - startFrame + 1;
    
    if (frameIndex < 1) {
      addLog(`计算结果Frame Index为${frameIndex}，必须大于等于1。请检查起始帧数和计算帧数的设置。`, 'error');
      return;
    }
    
    addLog(`起始帧数: ${startFrame}, 计算帧数: ${calculateFrame}, 实际Frame Index: ${frameIndex}`, 'info');
    
    // 保存CSV文件到临时目录
    const fileInfo = await saveCVFileToTemp(cvFile);
    addLog(`CSV文件已保存到临时目录: ${fileInfo.tempFilePath}`, 'info');
    addLog(`原始文件名: ${fileInfo.originalFileName}`, 'info');
    
    // 更新进度条到50%
    document.getElementById('cvProgressBar').style.width = '50%';
    document.getElementById('cvProgressText').textContent = '50%';
    
    // 调用Python脚本进行计算
    addLog('正在调用Python脚本计算离散系数...', 'info');
    const result = await pyAPI.runpyfile({
      scriptPath: './region_data_detail.py',
      pluginName: 'sofaData-process',
      args: [fileInfo.tempFilePath, frameIndex.toString(), fileInfo.originalFileName]
    });
    
    // 更新进度条到80%
    document.getElementById('cvProgressBar').style.width = '80%';
    document.getElementById('cvProgressText').textContent = '80%';
    
    if (result.success) {
      addLog('Python脚本执行成功', 'success');
      console.log('DEBUG: Python脚本原始输出:', result.data);
      
      // 解析结果
      const parsedData = parseRegionDataOutput(result.data);
      console.log('DEBUG: 解析后的数据:', parsedData);
      
      // 显示结果
      displayCVResults(parsedData.results);
      
      // 如果有文件名信息，显示在日志中
      if (parsedData.filename) {
        addLog(`处理的文件: ${parsedData.filename}`, 'info');
      }
      
      // 更新进度条到100%
      document.getElementById('cvProgressBar').style.width = '100%';
      document.getElementById('cvProgressText').textContent = '100%';
      
      addLog('离散系数计算完成', 'success');
      
      // 计算成功后显示"完成"并显示重置按钮
      calculateBtn.innerHTML = '<i class="bi bi-check-circle me-1"></i> 重新计算';
      calculateBtn.disabled = false;
      
      // 显示重置按钮组
      const resetButtonsContainer = document.getElementById('cvResetButtonsContainer');
      if (resetButtonsContainer) {
        resetButtonsContainer.style.display = 'block';
      }
    } else {
      addLog(`Python脚本执行失败: ${result.error}`, 'error');
      
      // 计算失败时恢复原始按钮状态
      calculateBtn.innerHTML = originalBtnText;
      calculateBtn.disabled = false;
    }
    
  } catch (error) {
    addLog(`计算离散系数时出错: ${error.message}`, 'error');
    console.error('离散系数计算错误:', error);
    
    // 出错时恢复原始按钮状态
    calculateBtn.innerHTML = originalBtnText;
    calculateBtn.disabled = false;
  }
}

// 保存CSV文件到临时目录
async function saveCVFileToTemp(file) {
  const reader = new FileReader();
  
  return new Promise((resolve, reject) => {
    reader.onload = async (e) => {
      try {
        const content = e.target.result;
        const tempFileName = `cv_temp_${Date.now()}.csv`;
        
        console.log('准备保存文件:', tempFileName);
        console.log('文件内容长度:', content.length);
        
        // 获取桌面路径作为临时目录
        let tempDir = '';
        try {
          const desktopResult = await fileAPI.getDesktopPath();
          if (desktopResult.success && desktopResult.filePath) {
            tempDir = `${desktopResult.filePath}\\temp`;
            // 确保临时目录存在
            await fileAPI.ensureDirectoryExists(tempDir);
          } else {
            throw new Error('无法获取桌面路径');
          }
        } catch (error) {
          console.error('获取临时目录失败:', error);
          // 使用当前目录的temp文件夹作为备选
          tempDir = 'temp';
        }
        
        const fullPath = `${tempDir}\\${tempFileName}`;
        console.log('完整文件路径:', fullPath);
        
        // 将文本内容转换为ArrayBuffer（参考其他功能的实现）
        const encoder = new TextEncoder();
        const arrayBuffer = encoder.encode(content);
        
        // 使用fileAPI.saveFile保存文件（与其他功能保持一致）
        await fileAPI.saveFile(fullPath, arrayBuffer);
        
        console.log('文件保存成功:', fullPath);
        resolve({
          tempFilePath: fullPath,
          originalFileName: cvOriginalFileName || file.name
        });
        
      } catch (error) {
        console.error('saveCVFileToTemp错误:', error);
        reject(error);
      }
    };
    
    reader.onerror = () => reject(new Error('文件读取失败'));
    reader.readAsText(file, 'utf-8');
  });
}

// 解析Python脚本输出
function parseRegionDataOutput(output) {
  try {
    // 解析调试数据
    const debugData = parseDebugData(output);
    
    // 查找JSON结果部分
    const jsonStartIndex = output.indexOf('JSON_RESULT_START');
    const jsonEndIndex = output.indexOf('JSON_RESULT_END');
    
    let parsedResult = { results: [], filename: null, frame_index: null };
    if (jsonStartIndex !== -1 && jsonEndIndex !== -1) {
      const jsonStr = output.substring(jsonStartIndex + 'JSON_RESULT_START'.length, jsonEndIndex).trim();
      const parsedData = JSON.parse(jsonStr);
      
      // 检查新的JSON格式（包含filename、frame_index和results）
      if (parsedData && typeof parsedData === 'object' && parsedData.results && Array.isArray(parsedData.results)) {
        parsedResult = {
          results: parsedData.results,
          filename: parsedData.filename,
          frame_index: parsedData.frame_index
        };
        addLog(`处理文件: ${parsedData.filename}, 帧索引: ${parsedData.frame_index}`, 'info');
      } else if (Array.isArray(parsedData)) {
        // 兼容旧格式（直接是results数组）
        parsedResult.results = parsedData;
      } else {
        addLog('JSON数据格式不正确', 'error');
        parsedResult.results = [];
      }
    } else {
      // 如果没有找到JSON格式，尝试解析文本输出
      const lines = output.split('\n');
      
      for (const line of lines) {
        if (line.includes('Region') && line.includes('有效点数')) {
          const match = line.match(/Region (\d+): 有效点数=(\d+), 平均值=([\d.]+), 标准差=([\d.]+), 离散系数=([\d.]+|inf)/);
          if (match) {
            parsedResult.results.push({
              region: parseInt(match[1]),
              valid_points: parseInt(match[2]),
              mean: parseFloat(match[3]),
              std_dev: parseFloat(match[4]),
              cv: match[5] === 'inf' ? 'inf' : parseFloat(match[5])
            });
          }
        }
      }
    }
    
    // 显示调试数据
    if (debugData && Object.keys(debugData).length > 0) {
      displayDebugData(debugData);
    }
    
    // 确保返回正确格式
    if (!Array.isArray(parsedResult.results)) {
      addLog('解析结果不是数组格式，返回空结果', 'warning');
      return { results: [], filename: null, frame_index: null };
    }
    
    return parsedResult;
  } catch (error) {
    addLog(`解析Python脚本输出时出错: ${error.message}`, 'error');
    return { results: [], filename: null, frame_index: null };
  }
}

// 解析调试数据
function parseDebugData(output) {
  const debugData = {};
  const lines = output.split('\n');
  let inDebugSection = false;
  let currentRegion = null;
  
  console.log('parseDebugData: 开始解析调试数据');
  console.log('parseDebugData: 输出内容:', output);
  
  for (const line of lines) {
    if (line.includes('=== 各Region提取的数据详情 ===')) {
      inDebugSection = true;
      console.log('parseDebugData: 找到调试数据开始标记');
      continue;
    }
    
    if (inDebugSection) {
      console.log('parseDebugData: 处理调试行:', line);
      
      // 匹配Region行: "Region 4: 提取到 64 个有效数据点"
      const regionMatch = line.match(/Region (\d+): 提取到 (\d+) 个有效数据点/);
      if (regionMatch) {
        currentRegion = parseInt(regionMatch[1]);
        debugData[currentRegion] = {
          count: parseInt(regionMatch[2]),
          data: []
        };
        console.log('parseDebugData: 找到Region', currentRegion, '数据点数量:', regionMatch[2]);
        continue;
      }
      
      // 匹配数据行: "  数据: [1.234, 2.345, ...]" 或 "  数据: [1.234, 2.345, ...]..."
      const dataMatch = line.match(/\s+数据: \[([\d.,\s]+)\](\.\.\.)?/);
      if (dataMatch && currentRegion !== null) {
        const dataStr = dataMatch[1];
        const values = dataStr.split(',').map(v => parseFloat(v.trim())).filter(v => !isNaN(v));
        debugData[currentRegion].data = values;
        console.log('parseDebugData: Region', currentRegion, '解析到数据:', values.length, '个值');
        continue;
      }
      
      // 匹配无数据行: "  无有效数据"
      if (line.includes('无有效数据') && currentRegion !== null) {
        debugData[currentRegion].data = [];
        console.log('parseDebugData: Region', currentRegion, '无有效数据');
        continue;
      }
      
      // 如果遇到其他内容，可能已经结束调试部分
      if (line.trim() && !line.startsWith('  ') && !line.startsWith('Region')) {
        console.log('parseDebugData: 调试部分结束，遇到行:', line);
        break;
      }
    }
  }
  
  console.log('parseDebugData: 最终解析结果:', debugData);
  return debugData;
}

// 显示调试数据
function displayDebugData(debugData) {
  console.log('displayDebugData: 开始显示调试数据', debugData);
  
  const debugContainer = document.getElementById('debugDataContainer');
  const debugAccordion = document.getElementById('debugAccordion');
  
  if (!debugContainer || !debugAccordion) {
    console.log('displayDebugData: 找不到调试数据容器元素');
    return;
  }
  
  // 清空现有内容
  debugAccordion.innerHTML = '';
  
  const regions = Object.keys(debugData).sort((a, b) => parseInt(a) - parseInt(b));
  
  regions.forEach((region, index) => {
    const data = debugData[region];
    const accordionItem = document.createElement('div');
    accordionItem.className = 'accordion-item';
    
    const headerId = `debugHeading${region}`;
    const collapseId = `debugCollapse${region}`;
    
    accordionItem.innerHTML = `
      <h2 class="accordion-header" id="${headerId}">
        <button class="accordion-button ${index === 0 ? '' : 'collapsed'}" type="button" data-bs-toggle="collapse" data-bs-target="#${collapseId}" aria-expanded="${index === 0 ? 'true' : 'false'}" aria-controls="${collapseId}">
          Region ${region} - ${data.count} 个数据点
        </button>
      </h2>
      <div id="${collapseId}" class="accordion-collapse collapse ${index === 0 ? 'show' : ''}" aria-labelledby="${headerId}" data-bs-parent="#debugAccordion">
        <div class="accordion-body">
          <div class="mb-2">
            <strong>数据点数量:</strong> ${data.count}
          </div>
          <div class="mb-2">
            <strong>提取的数据:</strong>
          </div>
          
          <!-- 徽章显示区域 -->
          <div class="debug-data-container" style="max-height: 200px; overflow-y: auto; background-color: #f8f9fa; padding: 10px; border-radius: 4px; font-family: monospace; font-size: 0.9em;">
            ${data.data.length > 0 ? 
              data.data.map((value, idx) => `<span class="badge bg-secondary me-1 mb-1">${value}</span>`).join('') : 
              '<span class="text-muted">无有效数据</span>'
            }
          </div>
          
          <!-- 复制按钮和统计信息 -->
          ${data.data.length > 0 ? `
            <div class="mt-2 d-flex justify-content-between align-items-center">
              <div class="text-muted small">
                前10个值: ${data.data.slice(0, 10).join(', ')}${data.data.length > 10 ? '...' : ''}
              </div>
              <div>
                <button class="btn btn-sm btn-outline-secondary" onclick="copyRegionData(${region})">
                  <i class="bi bi-clipboard me-1"></i>复制数据
                </button>
              </div>
            </div>
          ` : ''}
        </div>
      </div>
    `;
    
    debugAccordion.appendChild(accordionItem);
  });
  
  // 显示调试数据容器
  debugContainer.style.display = 'block';
  addLog(`显示了${regions.length}个Region的调试数据`, 'info');
  

  
  // 缓存调试数据用于验证功能
  cacheDebugData(debugData);
}

// 显示计算结果
function displayCVResults(results) {
  const tbody = document.querySelector('#cvResultsTable tbody');
  tbody.innerHTML = ''; // 清空现有结果
  
  if (results.length === 0) {
    const row = tbody.insertRow();
    const cell = row.insertCell();
    cell.colSpan = 5;
    cell.textContent = '没有找到有效的区域数据';
    cell.style.textAlign = 'center';
    return;
  }
  
  results.forEach(result => {
    const row = tbody.insertRow();
    
    // 区域
    const regionCell = row.insertCell();
    regionCell.textContent = `Region ${result.region}`;
    
    // 有效点数
    const pointsCell = row.insertCell();
    pointsCell.textContent = result.valid_points;
    
    // 平均值
    const meanCell = row.insertCell();
    meanCell.textContent = result.mean.toFixed(4);
    
    // 标准差
    const stdCell = row.insertCell();
    stdCell.textContent = result.std_dev.toFixed(4);
    
    // 离散系数
    const cvCell = row.insertCell();
    cvCell.textContent = result.cv === 'inf' ? '∞' : result.cv.toFixed(4);
  });
  
  // 显示结果表格
  document.getElementById('cvResultsContainer').style.display = 'block';
  addLog(`成功计算了${results.length}个区域的离散系数`, 'success');
  
  // 显示保存JSON按钮
  const saveJsonContainer = document.getElementById('saveJsonContainer');
  if (saveJsonContainer) {
    saveJsonContainer.style.display = 'block';
  }
  
  // 启用区域验证功能
  enableRegionValidation(results);
}

// ==================== 验证功能相关代码 ====================

// 存储计算结果和调试数据，用于验证
let calculationResults = [];
let debugDataCache = {};

// 启用区域验证功能
function enableRegionValidation(results) {
  calculationResults = results;
  
  // 启用区域验证按钮
  const regionValidationBtn = document.getElementById('regionValidationBtn');
  if (regionValidationBtn) {
    regionValidationBtn.disabled = false;
  }
  
  // 填充区域选择下拉框
  const regionSelect = document.getElementById('regionSelect');
  if (regionSelect) {
    regionSelect.innerHTML = '<option value="">请选择区域...</option>';
    results.forEach(result => {
      const option = document.createElement('option');
      option.value = result.region;
      option.textContent = `Region ${result.region} (${result.valid_points}个数据点)`;
      regionSelect.appendChild(option);
    });
  }
}

// 初始化验证功能事件监听器
function initValidationEventListeners() {
  // 手动验证按钮
  const manualValidationBtn = document.getElementById('manualValidationBtn');
  if (manualValidationBtn) {
    manualValidationBtn.addEventListener('click', showManualValidation);
  }
  
  // 区域验证按钮
  const regionValidationBtn = document.getElementById('regionValidationBtn');
  if (regionValidationBtn) {
    regionValidationBtn.addEventListener('click', showRegionValidation);
  }
  
  // 手动计算按钮
  const calculateManualBtn = document.getElementById('calculateManualBtn');
  if (calculateManualBtn) {
    calculateManualBtn.addEventListener('click', calculateManualValidation);
  }
  
  // 清空按钮
  const clearManualBtn = document.getElementById('clearManualBtn');
  if (clearManualBtn) {
    clearManualBtn.addEventListener('click', clearManualInput);
  }
  
  // 区域计算按钮
  const calculateRegionBtn = document.getElementById('calculateRegionBtn');
  if (calculateRegionBtn) {
    calculateRegionBtn.addEventListener('click', calculateRegionValidation);
  }
  
  // 区域选择变化
  const regionSelect = document.getElementById('regionSelect');
  if (regionSelect) {
    regionSelect.addEventListener('change', onRegionSelectChange);
  }
}

// 显示手动验证区域
function showManualValidation() {
  document.getElementById('manualValidationArea').style.display = 'block';
  document.getElementById('regionValidationArea').style.display = 'none';
  document.getElementById('validationResults').style.display = 'none';
}

// 显示区域验证区域
function showRegionValidation() {
  document.getElementById('manualValidationArea').style.display = 'none';
  document.getElementById('regionValidationArea').style.display = 'block';
  document.getElementById('validationResults').style.display = 'none';
}

// 区域选择变化处理
function onRegionSelectChange() {
  const regionSelect = document.getElementById('regionSelect');
  const calculateRegionBtn = document.getElementById('calculateRegionBtn');
  
  if (regionSelect.value) {
    calculateRegionBtn.disabled = false;
  } else {
    calculateRegionBtn.disabled = true;
  }
}

// 清空手动输入
function clearManualInput() {
  document.getElementById('manualDataInput').value = '';
  document.getElementById('validationResults').style.display = 'none';
}

// 解析手动输入的数据
function parseManualInput(inputText) {
  if (!inputText.trim()) {
    return [];
  }
  
  // 支持多种分隔符：逗号、空格、换行
  const values = inputText
    .replace(/[,\s\n\r]+/g, ',')
    .split(',')
    .map(v => v.trim())
    .filter(v => v !== '')
    .map(v => {
      const num = parseFloat(v);
      return isNaN(num) ? null : num;
    })
    .filter(v => v !== null && v !== 0 && v !== -1); // 过滤掉0和-1
  
  return values;
}

// 计算统计数据
function calculateStatistics(data) {
  if (data.length === 0) {
    return {
      count: 0,
      mean: 0,
      stdDev: 0,
      cv: 'inf'
    };
  }
  
  const count = data.length;
  const mean = data.reduce((sum, val) => sum + val, 0) / count;
  
  if (count === 1) {
    return {
      count: count,
      mean: mean,
      stdDev: 0,
      cv: 0
    };
  }
  
  // 计算样本标准差 (除以N-1)
  const variance = data.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (count - 1);
  const stdDev = Math.sqrt(variance);
  const cv = mean !== 0 ? stdDev / mean : 'inf';
  
  return {
    count: count,
    mean: mean,
    stdDev: stdDev,
    cv: cv
  };
}

// 手动验证计算
function calculateManualValidation() {
  const inputText = document.getElementById('manualDataInput').value;
  const data = parseManualInput(inputText);
  
  if (data.length === 0) {
    alert('请输入有效的数值数据');
    return;
  }
  
  const stats = calculateStatistics(data);
  
  // 尝试找到匹配的原始计算结果作为参考
  let matchingOriginal = null;
  let matchingRegion = null;
  
  if (calculationResults && calculationResults.length > 0) {
    // 查找数据点数相同的区域作为参考
    const matchingResult = calculationResults.find(result => result.valid_points === data.length);
    if (matchingResult) {
      matchingOriginal = matchingResult;
      matchingRegion = matchingResult.region;
    }
  }
  
  // 显示验证结果
  displayValidationResults({
    type: 'manual',
    inputData: data,
    calculated: stats,
    original: matchingOriginal,
    matchingRegion: matchingRegion
  });
  
  if (matchingOriginal) {
    addLog(`手动验证计算完成，使用了${data.length}个数据点，找到Region ${matchingRegion}作为参考对比`, 'success');
  } else {
    addLog(`手动验证计算完成，使用了${data.length}个数据点，未找到匹配的原始结果进行对比`, 'info');
  }
}

// 区域验证计算
function calculateRegionValidation() {
  const regionSelect = document.getElementById('regionSelect');
  const selectedRegion = parseInt(regionSelect.value);
  
  if (!selectedRegion) {
    alert('请选择要验证的区域');
    return;
  }
  
  // 查找原始计算结果
  const originalResult = calculationResults.find(r => r.region === selectedRegion);
  if (!originalResult) {
    alert('未找到该区域的原始计算结果');
    return;
  }
  
  // 获取该区域的调试数据
  const debugData = debugDataCache[selectedRegion];
  if (!debugData || !debugData.data || debugData.data.length === 0) {
    alert('未找到该区域的原始数据，无法进行验证');
    return;
  }
  
  // 使用原始数据重新计算
  const stats = calculateStatistics(debugData.data);
  
  // 显示验证结果
  displayValidationResults({
    type: 'region',
    region: selectedRegion,
    inputData: debugData.data,
    calculated: stats,
    original: originalResult
  });
  
  addLog(`Region ${selectedRegion}验证计算完成，使用了${debugData.data.length}个数据点`, 'success');
}

// 显示验证结果
function displayValidationResults(validationData) {
  const tbody = document.getElementById('validationResultsBody');
  const summaryDiv = document.getElementById('validationSummary');
  
  tbody.innerHTML = '';
  
  const { calculated, original, type, region, inputData, matchingRegion } = validationData;
  
  // 创建结果行
  const metrics = [
    { name: '数据点数', calculated: calculated.count, original: original?.valid_points },
    { name: '平均值', calculated: calculated.mean.toFixed(4), original: original?.mean?.toFixed(4) },
    { name: '标准差', calculated: calculated.stdDev.toFixed(4), original: original?.std_dev?.toFixed(4) },
    { name: '离散系数', calculated: calculated.cv === 'inf' ? '∞' : calculated.cv.toFixed(4), original: original?.cv === 'inf' ? '∞' : original?.cv?.toFixed(4) }
  ];
  
  let allMatch = true;
  
  metrics.forEach(metric => {
    const row = tbody.insertRow();
    
    // 计算项目
    const nameCell = row.insertCell();
    nameCell.textContent = metric.name;
    
    // 验证计算结果
    const calculatedCell = row.insertCell();
    calculatedCell.textContent = metric.calculated;
    
    // 原始计算结果
    const originalCell = row.insertCell();
    if (!metric.original) {
      originalCell.textContent = '无对比数据';
      originalCell.className = 'text-muted';
    } else {
      originalCell.textContent = metric.original;
    }
    
    // 差异
    const diffCell = row.insertCell();
    if (!metric.original) {
      diffCell.textContent = '-';
      diffCell.className = 'text-muted';
    } else {
      const calcVal = parseFloat(String(metric.calculated).replace('∞', 'Infinity'));
      const origVal = parseFloat(String(metric.original).replace('∞', 'Infinity'));
      
      if (isFinite(calcVal) && isFinite(origVal)) {
        const diff = Math.abs(calcVal - origVal);
        diffCell.textContent = diff.toFixed(6);
        if (diff < 0.0001) {
          diffCell.className = 'text-success';
        } else {
          diffCell.className = 'text-warning';
          allMatch = false;
        }
      } else if (calcVal === origVal) {
        diffCell.textContent = '0';
        diffCell.className = 'text-success';
      } else {
        diffCell.textContent = '不匹配';
        diffCell.className = 'text-danger';
        allMatch = false;
      }
    }
    
    // 状态
    const statusCell = row.insertCell();
    if (type === 'manual' && !metric.original) {
      statusCell.innerHTML = '<i class="bi bi-info-circle text-info"></i> 手动验证';
    } else if (!metric.original) {
      statusCell.innerHTML = '<i class="bi bi-dash-circle text-muted"></i> 无对比';
    } else {
      const calcVal = parseFloat(String(metric.calculated).replace('∞', 'Infinity'));
      const origVal = parseFloat(String(metric.original).replace('∞', 'Infinity'));
      
      if ((isFinite(calcVal) && isFinite(origVal) && Math.abs(calcVal - origVal) < 0.0001) || calcVal === origVal) {
        statusCell.innerHTML = '<i class="bi bi-check-circle text-success"></i> 匹配';
      } else {
        statusCell.innerHTML = '<i class="bi bi-x-circle text-danger"></i> 不匹配';
      }
    }
  });
  
  // 设置总结信息
  if (type === 'manual') {
    if (original && matchingRegion) {
      if (allMatch) {
        summaryDiv.className = 'alert alert-success';
        summaryDiv.innerHTML = `
          <i class="bi bi-check-circle me-2"></i>
          <strong>手动验证通过！</strong><br>
          使用了 ${inputData.length} 个数据点进行计算，与 Region ${matchingRegion} 的原始结果完全一致。
        `;
      } else {
        summaryDiv.className = 'alert alert-warning';
        summaryDiv.innerHTML = `
          <i class="bi bi-exclamation-triangle me-2"></i>
          <strong>手动验证发现差异</strong><br>
          使用了 ${inputData.length} 个数据点进行计算，与 Region ${matchingRegion} 的原始结果存在差异，请检查输入数据或计算逻辑。
        `;
      }
    } else {
      summaryDiv.className = 'alert alert-info';
      summaryDiv.innerHTML = `
        <i class="bi bi-info-circle me-2"></i>
        <strong>手动验证完成</strong><br>
        使用了 ${inputData.length} 个数据点进行计算。计算公式：平均值 = Σx/n，标准差 = √(Σ(x-μ)²/(n-1))，离散系数 = 标准差/平均值
      `;
    }
  } else {
    if (allMatch) {
      summaryDiv.className = 'alert alert-success';
      summaryDiv.innerHTML = `
        <i class="bi bi-check-circle me-2"></i>
        <strong>验证通过！</strong><br>
        Region ${region} 的计算结果与原始结果完全一致，程序计算正确。
      `;
    } else {
      summaryDiv.className = 'alert alert-warning';
      summaryDiv.innerHTML = `
        <i class="bi bi-exclamation-triangle me-2"></i>
        <strong>发现差异</strong><br>
        Region ${region} 的验证计算结果与原始结果存在差异，请检查计算逻辑或数据处理过程。
      `;
    }
  }
  
  // 显示验证结果区域
  document.getElementById('validationResults').style.display = 'block';
}

// 缓存调试数据
function cacheDebugData(debugData) {
  debugDataCache = {};
  // debugData的格式是 {region: {count: number, data: array}}
  Object.keys(debugData).forEach(region => {
    debugDataCache[parseInt(region)] = {
      region: parseInt(region),
      count: debugData[region].count,
      data: debugData[region].data
    };
  });
  console.log('缓存调试数据完成:', debugDataCache);
}

// 复制区域数据到剪贴板
function copyRegionData(region) {
  const data = debugDataCache[region];
  if (!data || !data.data || data.data.length === 0) {
    alert('该区域没有可复制的数据');
    return;
  }
  
  // 将数据转换为纯文本格式，每行一个数值
  const textData = data.data.join('\n');
  
  // 复制到剪贴板
  navigator.clipboard.writeText(textData).then(() => {
    // 显示成功提示
    showCopySuccess(`Region ${region}`, data.data.length);
  }).catch(err => {
    console.error('复制失败:', err);
    // 降级方案：使用传统方法
    fallbackCopyToClipboard(textData);
    showCopySuccess(`Region ${region}`, data.data.length);
  });
}



// 降级复制方案
function fallbackCopyToClipboard(text) {
  const textArea = document.createElement('textarea');
  textArea.value = text;
  textArea.style.position = 'fixed';
  textArea.style.left = '-999999px';
  textArea.style.top = '-999999px';
  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();
  
  try {
    document.execCommand('copy');
  } catch (err) {
    console.error('降级复制也失败了:', err);
  }
  
  document.body.removeChild(textArea);
}

// 显示复制成功提示
function showCopySuccess(regionName, dataCount) {
  // 创建临时提示元素
  const toast = document.createElement('div');
  toast.className = 'alert alert-success alert-dismissible fade show position-fixed';
  toast.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
  toast.innerHTML = `
    <i class="bi bi-check-circle me-2"></i>
    <strong>复制成功！</strong><br>
    已复制 ${regionName} 的 ${dataCount} 个数据点到剪贴板
    <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
  `;
  
  document.body.appendChild(toast);
  
  // 3秒后自动移除
  setTimeout(() => {
    if (toast.parentNode) {
      toast.parentNode.removeChild(toast);
    }
  }, 3000);
  
  addLog(`复制了${regionName}的${dataCount}个数据点`, 'success');
}

// 清除JSON文件功能
// 保存离散数据JSON文件的处理函数
async function handleSaveJsonFile() {
  try {
    if (!calculationResults || calculationResults.length === 0) {
      addLog('没有可保存的离散系数计算结果', 'warning');
      return;
    }
    
    addLog('开始保存离散数据JSON文件...', 'info');
    
    // 获取桌面路径
    const desktopResult = await fileAPI.getDesktopPath();
    if (!desktopResult.success) {
      throw new Error(`获取桌面路径失败: ${desktopResult.error}`);
    }
    
    const ergonomicDataFolder = `${desktopResult.filePath}\\Ergonomic data`;
    
    // 确保目标文件夹存在
    await fileAPI.ensureDirectoryExists(ergonomicDataFolder);
    
    // 获取原始CSV文件名（去掉扩展名）
    let baseFileName = 'lisan_data';
    if (cvOriginalFileName) {
      baseFileName = cvOriginalFileName.replace(/\.csv$/i, '');
    } else if (cvFile && cvFile.name) {
      baseFileName = cvFile.name.replace(/\.csv$/i, '');
    }
    
    // 构建JSON数据结构
    const jsonData = {
      fileName: baseFileName + '.csv', // 添加文件名字段
      lisan: {}
    };
    
    // 为每个region添加数据
    calculationResults.forEach(result => {
      const regionKey = `region_${result.region}`;
      jsonData.lisan[regionKey] = {
        "平均值": result.mean,
        "标准差": result.std_dev,
        "离散系数": result.cv === 'inf' ? 'infinity' : result.cv
      };
    });
    
    // 生成文件名：原CSV文件名 + '_lisan' 后缀
    const fileName = `${baseFileName}_lisan.json`;
    const filePath = `${ergonomicDataFolder}\\${fileName}`;
    
    // 保存JSON文件
    const jsonString = JSON.stringify(jsonData, null, 2);
    const saveResult = await fileAPI.writeFile(filePath, jsonString);
    
    if (saveResult.success) {
      addLog(`离散数据JSON文件保存成功: ${fileName}`, 'success');
      addLog(`保存路径: ${filePath}`, 'info');
      
      // 显示Element UI成功消息提示
      if (typeof ELEMENT !== 'undefined' && ELEMENT.Message) {
        ELEMENT.Message({
          message: `离散数据保存成功！文件已保存至: ${fileName}`,
          type: 'success',
          duration: 4000,
          showClose: true
        });
      }
    } else {
      throw new Error(`保存文件失败: ${saveResult.error}`);
    }
    
  } catch (error) {
    addLog(`保存离散数据JSON文件失败: ${error.message}`, 'error');
    console.error('保存离散数据JSON文件失败:', error);
    
    // 显示Element UI错误消息提示
    if (typeof ELEMENT !== 'undefined' && ELEMENT.Message) {
      ELEMENT.Message({
        message: `保存失败: ${error.message}`,
        type: 'error',
        duration: 5000,
        showClose: true
      });
    }
  }
}

async function handleClearJsonFiles() {
  const folderPath = document.getElementById('dataExtractionInputFolder').value.trim();
  
  if (!folderPath) {
    createExtractionAlert('danger', '请先设置输入文件夹路径');
    return;
  }
  
  // 弹出确认提示
  const confirmed = confirm('确定要清除该文件夹中的所有JSON文件吗？此操作不可撤销！');
  if (!confirmed) {
    return;
  }
  
  try {
    // 使用Electron的readDirectory方法读取目录
    const fileInfos = await window.fileAPI.readDirectory(folderPath);
    
    // 过滤出JSON文件（只取文件，不取目录）
    const jsonFiles = fileInfos
      .filter(fileInfo => fileInfo.isFile && fileInfo.name.toLowerCase().endsWith('.json'))
      .map(fileInfo => fileInfo.name);
    
    if (jsonFiles.length === 0) {
      createExtractionAlert('info', '该文件夹中没有找到JSON文件');
      return;
    }
    
    let deletedCount = 0;
    let errorCount = 0;
    
    // 逐个删除JSON文件
     for (const jsonFile of jsonFiles) {
       try {
         const filePath = folderPath.endsWith('\\') || folderPath.endsWith('/') 
           ? folderPath + jsonFile 
           : folderPath + '\\' + jsonFile;
         await window.fileAPI.deleteFile(filePath);
        deletedCount++;
        addLog(`已删除文件: ${jsonFile}`, 'info');
      } catch (error) {
        errorCount++;
        addLog(`删除文件失败: ${jsonFile} - ${error.message}`, 'error');
      }
    }
    
    // 显示结果
    if (errorCount === 0) {
      createExtractionAlert('success', `成功清除了 ${deletedCount} 个JSON文件`);
      addLog(`清除JSON文件完成，共删除 ${deletedCount} 个文件`, 'success');
    } else {
      createExtractionAlert('warning', `清除完成：成功删除 ${deletedCount} 个文件，失败 ${errorCount} 个文件`);
      addLog(`清除JSON文件完成，成功 ${deletedCount} 个，失败 ${errorCount} 个`, 'warning');
    }
    
  } catch (error) {
    createExtractionAlert('danger', `清除JSON文件失败: ${error.message}`);
    addLog(`清除JSON文件失败: ${error.message}`, 'error');
  }
}

async function handleClearXlsxFiles() {
  // 获取输入文件夹路径
  const folderPath = document.getElementById('dataExtractionInputFolder').value.trim();
  
  if (!folderPath) {
    createExtractionAlert('danger', '请先设置输入文件夹路径');
    return;
  }
  
  // 弹出确认提示
  const confirmed = confirm(`确定要清除文件夹 "${folderPath}" 中的所有xlsx文件吗？此操作不可撤销！`);
  if (!confirmed) {
    return;
  }
  
  try {
    // 使用Electron的readDirectory方法读取目录
    const fileInfos = await window.fileAPI.readDirectory(folderPath);
    
    // 过滤出xlsx文件（只取文件，不取目录）
    const xlsxFiles = fileInfos
      .filter(fileInfo => fileInfo.isFile && fileInfo.name.toLowerCase().endsWith('.xlsx'))
      .map(fileInfo => fileInfo.name);
    
    if (xlsxFiles.length === 0) {
      createExtractionAlert('info', '该文件夹中没有找到xlsx文件');
      return;
    }
    
    let deletedCount = 0;
    let errorCount = 0;
    
    // 逐个删除xlsx文件
    for (const xlsxFile of xlsxFiles) {
      try {
        const filePath = folderPath.endsWith('\\') || folderPath.endsWith('/') 
          ? folderPath + xlsxFile 
          : folderPath + '\\' + xlsxFile;
        await window.fileAPI.deleteFile(filePath);
        deletedCount++;
        addLog(`已删除文件: ${xlsxFile}`, 'info');
      } catch (error) {
        errorCount++;
        addLog(`删除文件失败: ${xlsxFile} - ${error.message}`, 'error');
      }
    }
    
    // 显示结果
    if (errorCount === 0) {
      createExtractionAlert('success', `成功清除了 ${deletedCount} 个xlsx文件`);
      addLog(`清除xlsx文件完成，共删除 ${deletedCount} 个文件`, 'success');
    } else {
      createExtractionAlert('warning', `清除完成：成功删除 ${deletedCount} 个文件，失败 ${errorCount} 个文件`);
      addLog(`清除xlsx文件完成，成功 ${deletedCount} 个，失败 ${errorCount} 个`, 'warning');
    }
    
  } catch (error) {
    createExtractionAlert('danger', `清除xlsx文件失败: ${error.message}`);
    addLog(`清除xlsx文件失败: ${error.message}`, 'error');
  }
}

// 绑定清除按钮事件
document.addEventListener('DOMContentLoaded', () => {
  const clearJsonBtn = document.getElementById('clearJsonBtn');
  if (clearJsonBtn) {
    clearJsonBtn.addEventListener('click', handleClearJsonFiles);
  }
  
  const clearXlsxBtn = document.getElementById('clearXlsxBtn');
  if (clearXlsxBtn) {
    clearXlsxBtn.addEventListener('click', handleClearXlsxFiles);
  }
  
  // 绑定文件浏览按钮事件
  console.log('开始绑定浏览按钮事件');
  
  const browseBaseJsonBtn = document.getElementById('browseBaseJsonBtn');
  if (browseBaseJsonBtn) {
    browseBaseJsonBtn.addEventListener('click', selectBaseJsonFile);
    console.log('Base JSON浏览按钮事件绑定成功');
  } else {
    console.error('未找到 browseBaseJsonBtn 元素');
  }
  
  const browseLisanJsonBtn = document.getElementById('browseLisanJsonBtn');
  if (browseLisanJsonBtn) {
    browseLisanJsonBtn.addEventListener('click', selectLisanJsonFile);
    console.log('Lisan JSON浏览按钮事件绑定成功');
  } else {
    console.error('未找到 browseLisanJsonBtn 元素');
  }
  
  // Word模板文件浏览按钮事件监听
  const browseWordTemplateBtn = document.getElementById('browseWordTemplateBtn');
  if (browseWordTemplateBtn) {
    browseWordTemplateBtn.addEventListener('click', selectWordTemplateFile);
    console.log('Word模板文件浏览按钮事件绑定成功');
  } else {
    console.error('未找到 browseWordTemplateBtn 元素');
  }
});

/**
 * 选择Base JSON文件
 */
async function selectBaseJsonFile() {
  console.log('selectBaseJsonFile 函数被调用');  
  try {
    if (window.fileAPI && window.fileAPI.showOpenDialog) {
      const result = await window.fileAPI.showOpenDialog({
        title: '选择Base JSON数据文件',
        defaultPath: 'C:\\Users\\Glenn_Gao\\Desktop',
        filters: [
          { name: 'JSON文件', extensions: ['json'] },
          { name: '所有文件', extensions: ['*'] }
        ],
        properties: ['openFile']
      });
      
      console.log('showOpenDialog 返回结果:', result);
      
      if (result.success && result.data && !result.data.canceled && result.data.filePaths && result.data.filePaths.length > 0) {
        const filePath = result.data.filePaths[0];
        document.getElementById('baseJsonFile').value = filePath;
        addLog(`已选择Base JSON文件: ${filePath}`, 'info');
      } else if (result.success && result.data && result.data.canceled) {
        addLog('用户取消了Base JSON文件选择', 'info');
      } else {
        addLog(`选择Base JSON文件失败: ${result.error || '未知错误'}`, 'error');
      }
    } else {
      console.log('fileAPI 不可用:', { fileAPI: window.fileAPI, showOpenDialog: window.fileAPI?.showOpenDialog });
      addLog('文件选择API不可用', 'error');
    }
  } catch (error) {
    addLog(`选择Base JSON文件失败: ${error.message}`, 'error');
    console.error('选择Base JSON文件失败:', error);
  }
}

/**
 * 选择Lisan JSON文件
 */
async function selectLisanJsonFile() {
  try {
    if (window.fileAPI && window.fileAPI.showOpenDialog) {
      const result = await window.fileAPI.showOpenDialog({
        title: '选择Lisan JSON数据文件',
        // defaultPath: 'C:\\Users\\Glenn_Gao\\Desktop',
        filters: [
          { name: 'JSON文件', extensions: ['json'] },
          { name: '所有文件', extensions: ['*'] }
        ],
        properties: ['openFile']
      });
      
      if (result.success && result.data && !result.data.canceled && result.data.filePaths && result.data.filePaths.length > 0) {
        const filePath = result.data.filePaths[0];
        document.getElementById('lisanJsonFile').value = filePath;
        console.log(`已选择Lisan JSON文件: ${filePath}`, 'info');
      } else if (result.success && result.data && result.data.canceled) {
        console.log('用户取消了Lisan JSON文件选择', 'info');
      } else {
        console.log(`选择Lisan JSON文件失败: ${result.error || '未知错误'}`, 'error');
      }
    } else {
      console.log('文件选择API不可用', 'error');
    }
  } catch (error) {
    console.log(`选择Lisan JSON文件失败: ${error.message}`, 'error');
    console.error('选择Lisan JSON文件失败:', error);
  }
}

/**
 * 选择Word模板文件
 */
async function selectWordTemplateFile() {
  console.log('selectWordTemplateFile 函数被调用');
  try {
    if (window.fileAPI && window.fileAPI.showOpenDialog) {
      const result = await window.fileAPI.showOpenDialog({
        title: '选择Word模板文件',
        // defaultPath: 'C:\\Users\\Glenn_Gao\\Desktop',
        filters: [
          { name: 'Word文档', extensions: ['docx', 'doc'] },
          { name: '所有文件', extensions: ['*'] }
        ],
        properties: ['openFile']
      });
      
      console.log('showOpenDialog 返回结果:', result);
      
      if (result.success && result.data && !result.data.canceled && result.data.filePaths && result.data.filePaths.length > 0) {
        const filePath = result.data.filePaths[0];
        document.getElementById('wordTemplateFile').value = filePath;
        addLog(`已选择Word模板文件: ${filePath}`, 'info');
      } else if (result.success && result.data && result.data.canceled) {
        addLog('用户取消了Word模板文件选择', 'info');
      } else {
        addLog(`选择Word模板文件失败: ${result.error || '未知错误'}`, 'error');
      }
    } else {
      console.log('fileAPI 不可用:', { fileAPI: window.fileAPI, showOpenDialog: window.fileAPI?.showOpenDialog });
      addLog('文件选择API不可用', 'error');
    }
  } catch (error) {
    addLog(`选择Word模板文件失败: ${error.message}`, 'error');
    console.error('选择Word模板文件失败:', error);
  }
}
